diff --git a/package-lock.json b/package-lock.json
index b7e325721b0cfe0e22a140792806184c38122c24..f7620ff19c88bf6c050ca2c1e73dbe67f8533483 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -20,28 +20,31 @@
         "@angular/router": "~13.3.0",
         "@ngx-translate/core": "^14.0.0",
         "@ngx-translate/http-loader": "^6.0.0",
-        "@tiptap/core": "^2.0.0-beta.175",
-        "@tiptap/extension-blockquote": "^2.0.0-beta.26",
-        "@tiptap/extension-bubble-menu": "^2.0.0-beta.56",
-        "@tiptap/extension-bullet-list": "^2.0.0-beta.26",
-        "@tiptap/extension-color": "^2.0.0-beta.9",
-        "@tiptap/extension-floating-menu": "^2.0.0-beta.51",
-        "@tiptap/extension-font-family": "^2.0.0-beta.21",
-        "@tiptap/extension-heading": "^2.0.0-beta.26",
-        "@tiptap/extension-highlight": "^2.0.0-beta.33",
-        "@tiptap/extension-image": "^2.0.0-beta.27",
-        "@tiptap/extension-list-item": "^2.0.0-beta.20",
-        "@tiptap/extension-ordered-list": "^2.0.0-beta.27",
-        "@tiptap/extension-paragraph": "^2.0.0-beta.23",
-        "@tiptap/extension-strike": "~2.0.0-beta.27",
-        "@tiptap/extension-subscript": "^2.0.0-beta.10",
-        "@tiptap/extension-superscript": "^2.0.0-beta.10",
-        "@tiptap/extension-text-align": "^2.0.0-beta.29",
-        "@tiptap/extension-text-style": "^2.0.0-beta.23",
-        "@tiptap/extension-underline": "^2.0.0-beta.23",
-        "@tiptap/starter-kit": "2.0.0-beta.184",
-        "ngx-tiptap": "^3.0.4",
-        "prosemirror-state": "^1.3.4",
+        "@tiptap/core": "^2.0.0-beta.182",
+        "@tiptap/extension-blockquote": "^2.0.0-beta.29",
+        "@tiptap/extension-bold": "^2.0.0-beta.28",
+        "@tiptap/extension-bubble-menu": "^2.0.0-beta.61",
+        "@tiptap/extension-bullet-list": "^2.0.0-beta.29",
+        "@tiptap/extension-color": "^2.0.0-beta.12",
+        "@tiptap/extension-document": "^2.0.0-beta.17",
+        "@tiptap/extension-floating-menu": "^2.0.0-beta.56",
+        "@tiptap/extension-font-family": "^2.0.0-beta.24",
+        "@tiptap/extension-heading": "^2.0.0-beta.29",
+        "@tiptap/extension-highlight": "^2.0.0-beta.35",
+        "@tiptap/extension-image": "^2.0.0-beta.30",
+        "@tiptap/extension-italic": "^2.0.0-beta.28",
+        "@tiptap/extension-list-item": "^2.0.0-beta.23",
+        "@tiptap/extension-ordered-list": "^2.0.0-beta.30",
+        "@tiptap/extension-paragraph": "^2.0.0-beta.26",
+        "@tiptap/extension-strike": "~2.0.0-beta.29",
+        "@tiptap/extension-subscript": "^2.0.0-beta.13",
+        "@tiptap/extension-superscript": "^2.0.0-beta.13",
+        "@tiptap/extension-text": "^2.0.0-beta.17",
+        "@tiptap/extension-text-align": "^2.0.0-beta.31",
+        "@tiptap/extension-text-style": "^2.0.0-beta.26",
+        "@tiptap/extension-underline": "^2.0.0-beta.25",
+        "ngx-tiptap": "^5.0.0",
+        "prosemirror-state": "^1.4.1",
         "rxjs": "^7.4.0",
         "testcafe": "^1.18.6",
         "tslib": "^2.1.0",
@@ -51,7 +54,7 @@
         "@angular-devkit/build-angular": "~13.3.0",
         "@angular/cli": "~13.3.0",
         "@angular/compiler-cli": "~13.3.0",
-        "@iqb/eslint-config": "^1.1.1",
+        "@iqb/eslint-config": "^2.1.1",
         "@types/jasmine": "~3.6.0",
         "@types/node": "^12.11.7",
         "iqb-dev-components": "^1.4.0",
@@ -2464,15 +2467,16 @@
       }
     },
     "node_modules/@eslint/eslintrc": {
-      "version": "1.2.3",
-      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.3.tgz",
-      "integrity": "sha512-uGo44hIwoLGNyduRpjdEpovcbMdd+Nv7amtmJxnKmI8xj6yd5LncmSwDa5NgX/41lIFJtkjD6YdVfgEzPfJ5UA==",
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz",
+      "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "ajv": "^6.12.4",
         "debug": "^4.3.2",
         "espree": "^9.3.2",
-        "globals": "^13.9.0",
+        "globals": "^13.15.0",
         "ignore": "^5.2.0",
         "import-fresh": "^3.2.1",
         "js-yaml": "^4.1.0",
@@ -2488,6 +2492,7 @@
       "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
       "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "fast-deep-equal": "^3.1.1",
         "fast-json-stable-stringify": "^2.0.0",
@@ -2503,13 +2508,15 @@
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
       "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "node_modules/@eslint/eslintrc/node_modules/globals": {
-      "version": "13.15.0",
-      "resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz",
-      "integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==",
+      "version": "13.17.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz",
+      "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "type-fest": "^0.20.2"
       },
@@ -2525,6 +2532,7 @@
       "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
       "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "argparse": "^2.0.1"
       },
@@ -2536,13 +2544,15 @@
       "version": "0.4.1",
       "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
       "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "node_modules/@eslint/eslintrc/node_modules/minimatch": {
       "version": "3.1.2",
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
       "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "brace-expansion": "^1.1.7"
       },
@@ -2555,6 +2565,7 @@
       "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
       "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
       "dev": true,
+      "peer": true,
       "engines": {
         "node": ">=10"
       },
@@ -2573,6 +2584,7 @@
       "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz",
       "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "@humanwhocodes/object-schema": "^1.2.1",
         "debug": "^4.1.1",
@@ -2586,19 +2598,19 @@
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
       "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "node_modules/@iqb/eslint-config": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/@iqb/eslint-config/-/eslint-config-1.1.1.tgz",
-      "integrity": "sha512-KaAdhBSnCXXfxeQRI51tZxgW58FXkAvHSFvZE38b+gvKPZ5YVYXuX0dlEEu7rYezeW7jCOk6zRtdkUbB5DJVyg==",
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/@iqb/eslint-config/-/eslint-config-2.1.1.tgz",
+      "integrity": "sha512-F94TVoZ0xT4mvxKdr9efDiRG74M0TQERCH2Eh4AL1u1JseDqYwbNhcnItadvdjho9USt9sMLDdxwOnADfHkE1g==",
       "dev": true,
-      "dependencies": {
-        "@typescript-eslint/eslint-plugin": "^5.19.0",
-        "@typescript-eslint/parser": "^5.19.0",
-        "eslint": "^8.13.0",
-        "eslint-config-airbnb-typescript": "^17.0.0",
-        "eslint-plugin-import": "^2.26.0"
+      "peerDependencies": {
+        "@typescript-eslint/eslint-plugin": "^5.30.0",
+        "@typescript-eslint/parser": "^5.30.0",
+        "eslint": "^8.18.0",
+        "eslint-config-airbnb-typescript": "^17.0.0"
       }
     },
     "node_modules/@istanbuljs/load-nyc-config": {
@@ -2859,24 +2871,17 @@
       }
     },
     "node_modules/@tiptap/core": {
-      "version": "2.0.0-beta.175",
-      "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.0.0-beta.175.tgz",
-      "integrity": "sha512-dDf+2GtifskNLysn49kaCIz0o5hf6VDZ8J7jSQAfoPDEkEkfw9OKhWrR7NzWW6J34CSJreFDRiWkGt8Qz283Vg==",
-      "dependencies": {
-        "@types/prosemirror-commands": "^1.0.4",
-        "@types/prosemirror-keymap": "^1.0.4",
-        "@types/prosemirror-model": "^1.16.0",
-        "@types/prosemirror-schema-list": "^1.0.3",
-        "@types/prosemirror-state": "^1.2.8",
-        "@types/prosemirror-transform": "^1.1.5",
-        "@types/prosemirror-view": "^1.23.1",
-        "prosemirror-commands": "^1.2.1",
-        "prosemirror-keymap": "^1.1.5",
-        "prosemirror-model": "^1.16.1",
-        "prosemirror-schema-list": "^1.1.6",
-        "prosemirror-state": "^1.3.4",
-        "prosemirror-transform": "^1.3.3",
-        "prosemirror-view": "^1.23.6"
+      "version": "2.0.0-beta.182",
+      "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.0.0-beta.182.tgz",
+      "integrity": "sha512-MZGkMGnVnWhBzjvpBNwQ9zBz38ndi3Irbf90uCTSArR0kaCVkW4vmyuPuOXd+0SO8Yv/l5oyDdOCpaG3rnQYfw==",
+      "dependencies": {
+        "prosemirror-commands": "1.3.0",
+        "prosemirror-keymap": "1.2.0",
+        "prosemirror-model": "1.18.1",
+        "prosemirror-schema-list": "1.2.0",
+        "prosemirror-state": "1.4.1",
+        "prosemirror-transform": "1.6.0",
+        "prosemirror-view": "1.26.2"
       },
       "funding": {
         "type": "github",
@@ -2884,9 +2889,9 @@
       }
     },
     "node_modules/@tiptap/extension-blockquote": {
-      "version": "2.0.0-beta.26",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-2.0.0-beta.26.tgz",
-      "integrity": "sha512-A6yjcYovONJfOjQFk6vDYXswaCdCtCwjL7w9VTB0R2DLTuJvvRt9DWN0IDcMrj5G+aMgDq4GUUTitv+2Y8krDg==",
+      "version": "2.0.0-beta.29",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-2.0.0-beta.29.tgz",
+      "integrity": "sha512-zMYT5TtpKWav9VhTn4JLyMvXmhEdbD6on0MdhcTjRm0I5ugyR4ZbJwh2aelM7G9DZVYzB8jZU18OSDJmo7Af7w==",
       "funding": {
         "type": "github",
         "url": "https://github.com/sponsors/ueberdosis"
@@ -2896,9 +2901,9 @@
       }
     },
     "node_modules/@tiptap/extension-bold": {
-      "version": "2.0.0-beta.26",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-2.0.0-beta.26.tgz",
-      "integrity": "sha512-pnO0I5sEQM3pmowjMGQ74adLzvc6HqGyLyqMizaGMicPu9uTYlSdId+qckYEEgPwPMaEShtv2Vg+ZHs7KVqfcg==",
+      "version": "2.0.0-beta.28",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-2.0.0-beta.28.tgz",
+      "integrity": "sha512-DY8GOzw9xjmTFrnvTbgHUNxTnDfKrkDgrhe0SUvdkT2udntWp8umPdhPiD3vczLgHOJw6tX68qMRjbsR1ZPcHQ==",
       "funding": {
         "type": "github",
         "url": "https://github.com/sponsors/ueberdosis"
@@ -2908,12 +2913,12 @@
       }
     },
     "node_modules/@tiptap/extension-bubble-menu": {
-      "version": "2.0.0-beta.56",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.0.0-beta.56.tgz",
-      "integrity": "sha512-nZozwauICdaNPmDPrSn1JFd/9/2rLtK8i2vBOcqxWHObVROvu8ZlJspnrJv23vS6P7/ZO3e/QLVHpnn+1yVq3g==",
+      "version": "2.0.0-beta.61",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.0.0-beta.61.tgz",
+      "integrity": "sha512-T3Yx+y1sUnXAJjK1CUfsQewSxOpDca9KzKqN2H9c9RZ9UlorR9XmZg6YYW7m9a7adeihj+o3cCO9jRd8dV+nnA==",
       "dependencies": {
-        "prosemirror-state": "^1.3.4",
-        "prosemirror-view": "^1.23.6",
+        "prosemirror-state": "1.4.1",
+        "prosemirror-view": "1.26.2",
         "tippy.js": "^6.3.7"
       },
       "funding": {
@@ -2925,36 +2930,9 @@
       }
     },
     "node_modules/@tiptap/extension-bullet-list": {
-      "version": "2.0.0-beta.26",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-2.0.0-beta.26.tgz",
-      "integrity": "sha512-1n5HV8gY1tLjPk4x48nva6SZlFHoPlRfF6pqSu9JcJxPO7FUSPxUokuz4swYNe0LRrtykfyNz44dUcxKVhoFow==",
-      "funding": {
-        "type": "github",
-        "url": "https://github.com/sponsors/ueberdosis"
-      },
-      "peerDependencies": {
-        "@tiptap/core": "^2.0.0-beta.1"
-      }
-    },
-    "node_modules/@tiptap/extension-code": {
-      "version": "2.0.0-beta.26",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-2.0.0-beta.26.tgz",
-      "integrity": "sha512-QcFWdEFfbJ1n5UFFBD17QPPAJ3J5p/b7XV484u0shCzywO7aNPV32QeHy1z0eMoyZtCbOWf6hg/a7Ugv8IwpHw==",
-      "funding": {
-        "type": "github",
-        "url": "https://github.com/sponsors/ueberdosis"
-      },
-      "peerDependencies": {
-        "@tiptap/core": "^2.0.0-beta.1"
-      }
-    },
-    "node_modules/@tiptap/extension-code-block": {
-      "version": "2.0.0-beta.37",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-2.0.0-beta.37.tgz",
-      "integrity": "sha512-mJAM+PHaNoKRYwM3D36lZ51/aoPxxvZNQn3UBnZ6G7l0ZJSgB3JvBEzqK6S8nNFeYIIxGwv4QF6vXe4MG9ie2g==",
-      "dependencies": {
-        "prosemirror-state": "^1.3.4"
-      },
+      "version": "2.0.0-beta.29",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-2.0.0-beta.29.tgz",
+      "integrity": "sha512-R8VB2l1ZB6VeGWx/t/04nBS5Wg3qjIDEZCpPihj2fccJOw99Lu0Ub2UJg/SfdGmeNNpBh4ZYYFv1g/XjyzlXKg==",
       "funding": {
         "type": "github",
         "url": "https://github.com/sponsors/ueberdosis"
@@ -2964,9 +2942,9 @@
       }
     },
     "node_modules/@tiptap/extension-color": {
-      "version": "2.0.0-beta.9",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-color/-/extension-color-2.0.0-beta.9.tgz",
-      "integrity": "sha512-c8zcaNCdwUwbgrutfsG7LD9KH7ZvDVwKOZHbOL4gMSwdH9s+6r1ThRFLEbKgHIJlTa2jd96qoo+lVfj1Qwp7ww==",
+      "version": "2.0.0-beta.12",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-color/-/extension-color-2.0.0-beta.12.tgz",
+      "integrity": "sha512-ddFIUdb7e0gLlYlcQiyZ+zRC4nXtpX2bhOHZ7IdCasoHYEWs/8dsncngLtymAgsRBeruMZ5K6ZhAYtgQVUugqQ==",
       "funding": {
         "type": "github",
         "url": "https://github.com/sponsors/ueberdosis"
@@ -2977,25 +2955,9 @@
       }
     },
     "node_modules/@tiptap/extension-document": {
-      "version": "2.0.0-beta.15",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-2.0.0-beta.15.tgz",
-      "integrity": "sha512-ypENC+xUYD5m2t+KOKNYqyXnanXd5fxyIyhR1qeEEwwQwMXGNrO3kCH6O4mIDCpy+/WqHvVay2tV5dVsXnvY8w==",
-      "funding": {
-        "type": "github",
-        "url": "https://github.com/sponsors/ueberdosis"
-      },
-      "peerDependencies": {
-        "@tiptap/core": "^2.0.0-beta.1"
-      }
-    },
-    "node_modules/@tiptap/extension-dropcursor": {
-      "version": "2.0.0-beta.25",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-2.0.0-beta.25.tgz",
-      "integrity": "sha512-GYf5s6dkZtsDy+TEkrQK6kLbfbitG4qnk02D+FlhlJMI/Nnx8rYCRJbwEHDdqrfX7XwZzULMqqqHvzxZYrEeNg==",
-      "dependencies": {
-        "@types/prosemirror-dropcursor": "^1.0.3",
-        "prosemirror-dropcursor": "^1.4.0"
-      },
+      "version": "2.0.0-beta.17",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-2.0.0-beta.17.tgz",
+      "integrity": "sha512-L6sg0FNchbtIpQkCSjMmItVGs3/vep8Fq56WRtDc1wBSGUSmtHaxQG7F2FZLnNIUMuvzVMRD81m2vYG73WkY6A==",
       "funding": {
         "type": "github",
         "url": "https://github.com/sponsors/ueberdosis"
@@ -3005,12 +2967,12 @@
       }
     },
     "node_modules/@tiptap/extension-floating-menu": {
-      "version": "2.0.0-beta.51",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-2.0.0-beta.51.tgz",
-      "integrity": "sha512-rEe7jADK9xr2n2LJsrGEN3Dz7sEGC1JT/7AdTdaZBxQRQvwxTjomqYGrt+LnX+v0MYggh6swMzj7upJosnKbBg==",
+      "version": "2.0.0-beta.56",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-2.0.0-beta.56.tgz",
+      "integrity": "sha512-j/evHE/6UPGkIgXny9IGcAh0IrcnQmg0b2NBYebs2mqx9xYKYoe+0jVgNdLp/0M3MRgQCzyWTyatBDBFOUR2mw==",
       "dependencies": {
-        "prosemirror-state": "^1.3.4",
-        "prosemirror-view": "^1.23.6",
+        "prosemirror-state": "1.4.1",
+        "prosemirror-view": "1.26.2",
         "tippy.js": "^6.3.7"
       },
       "funding": {
@@ -3022,9 +2984,9 @@
       }
     },
     "node_modules/@tiptap/extension-font-family": {
-      "version": "2.0.0-beta.21",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-font-family/-/extension-font-family-2.0.0-beta.21.tgz",
-      "integrity": "sha512-5KVCtuEBf1QyZxs/IOL0CPDtB5X3rk8QdDB8fB+UlASa6c/Dq59Uo2aObGOgAWNDdY0Vd9MmuDTvnJKP2LI2Ng==",
+      "version": "2.0.0-beta.24",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-font-family/-/extension-font-family-2.0.0-beta.24.tgz",
+      "integrity": "sha512-R7fgyJb4X6KS2Xcr73dYDxM1NSBNIQrtHLeSa3Cfc3Y9UDqeMFUIEgYUh4sBLBi3Z8Y9D3RRMvxN1x39j5eLLA==",
       "funding": {
         "type": "github",
         "url": "https://github.com/sponsors/ueberdosis"
@@ -3034,38 +2996,10 @@
         "@tiptap/extension-text-style": "^2.0.0-beta.1"
       }
     },
-    "node_modules/@tiptap/extension-gapcursor": {
-      "version": "2.0.0-beta.34",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-2.0.0-beta.34.tgz",
-      "integrity": "sha512-Vm8vMWWQ2kJcUOLfB5CEo5pYgyudI7JeeiZvX9ScPmUmgKVYhEpt3EAICY9pUYJ41aAVH35gZLXkUtsz2f9GHw==",
-      "dependencies": {
-        "@types/prosemirror-gapcursor": "^1.0.4",
-        "prosemirror-gapcursor": "^1.2.1"
-      },
-      "funding": {
-        "type": "github",
-        "url": "https://github.com/sponsors/ueberdosis"
-      },
-      "peerDependencies": {
-        "@tiptap/core": "^2.0.0-beta.1"
-      }
-    },
-    "node_modules/@tiptap/extension-hard-break": {
-      "version": "2.0.0-beta.30",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-2.0.0-beta.30.tgz",
-      "integrity": "sha512-X9xj/S+CikrbIE7ccUFVwit5QHEbflnKVxod+4zPwr1cxogFbE9AyLZE2MpYdx3z9LcnTYYi9leBqFrP4T/Olw==",
-      "funding": {
-        "type": "github",
-        "url": "https://github.com/sponsors/ueberdosis"
-      },
-      "peerDependencies": {
-        "@tiptap/core": "^2.0.0-beta.1"
-      }
-    },
     "node_modules/@tiptap/extension-heading": {
-      "version": "2.0.0-beta.26",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-2.0.0-beta.26.tgz",
-      "integrity": "sha512-nR6W/3rjnZH1Swo7tGBoYsmO6xMvu9MGq6jlm3WVHCB7B3CsrRvCkTwGjVIbKTaZC4bQfx5gvAUpQFvwuU+M5w==",
+      "version": "2.0.0-beta.29",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-2.0.0-beta.29.tgz",
+      "integrity": "sha512-q92jYcsT5bPhvuQaB0h44Z9r+Ii22tDYo082KMVnR4+tknHT/3xx+p4JC8KHjh+/5W8Quyafqy6mS8L8VX0zsQ==",
       "funding": {
         "type": "github",
         "url": "https://github.com/sponsors/ueberdosis"
@@ -3075,40 +3009,9 @@
       }
     },
     "node_modules/@tiptap/extension-highlight": {
-      "version": "2.0.0-beta.33",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-highlight/-/extension-highlight-2.0.0-beta.33.tgz",
-      "integrity": "sha512-TXyMiCcY5a0w5UFax350xU+T79GKJw2XwJ6Punc6sY2RRRgKaEbN1ZF0JCdQhQvD1ooKImHzCRYR8Pldb0xgfg==",
-      "funding": {
-        "type": "github",
-        "url": "https://github.com/sponsors/ueberdosis"
-      },
-      "peerDependencies": {
-        "@tiptap/core": "^2.0.0-beta.1"
-      }
-    },
-    "node_modules/@tiptap/extension-history": {
-      "version": "2.0.0-beta.21",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-history/-/extension-history-2.0.0-beta.21.tgz",
-      "integrity": "sha512-0v8Cl30V4dsabdpspLdk+f+lMoIvLFlJN5WRxtc7RRZ5gfJVxPHwooIKdvC51brfh/oJtWFCNMRjhoz0fRaF9A==",
-      "dependencies": {
-        "@types/prosemirror-history": "^1.0.3",
-        "prosemirror-history": "^1.2.0"
-      },
-      "funding": {
-        "type": "github",
-        "url": "https://github.com/sponsors/ueberdosis"
-      },
-      "peerDependencies": {
-        "@tiptap/core": "^2.0.0-beta.1"
-      }
-    },
-    "node_modules/@tiptap/extension-horizontal-rule": {
-      "version": "2.0.0-beta.31",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.0.0-beta.31.tgz",
-      "integrity": "sha512-MNc4retfjRgkv3qxqGya0+/BEd1Kmn+oMsCRvE+8x3sXyKIse+vdqMuG5qUcA6np0ZD/9hh1riiQ1GQdgc23Ng==",
-      "dependencies": {
-        "prosemirror-state": "^1.3.4"
-      },
+      "version": "2.0.0-beta.35",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-highlight/-/extension-highlight-2.0.0-beta.35.tgz",
+      "integrity": "sha512-xvEKOyuTj4mhQ8GIOItaSymJhGkWt2gGuCvmFWnTVZAaJJQOlgUTdkmayLCtwoDDP7biiuDhRJokTukGGmhUZw==",
       "funding": {
         "type": "github",
         "url": "https://github.com/sponsors/ueberdosis"
@@ -3118,9 +3021,9 @@
       }
     },
     "node_modules/@tiptap/extension-image": {
-      "version": "2.0.0-beta.27",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-image/-/extension-image-2.0.0-beta.27.tgz",
-      "integrity": "sha512-kdJ7V39yNdVWUco/RBe7WgvFevd81l+pU6+Je9HpelqBBP953wDttzLMuAWQB4AeLv9WhKSlORHiFv2SKsV5NA==",
+      "version": "2.0.0-beta.30",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-image/-/extension-image-2.0.0-beta.30.tgz",
+      "integrity": "sha512-VhEmgiKkZMiKR7hbpJgIlIUS/QNjSGI5ER7mKDAbuV1IB5yb6nGjZ6o3Exrr2/CaTaW5hQarBC1z2Xgdu05EGg==",
       "funding": {
         "type": "github",
         "url": "https://github.com/sponsors/ueberdosis"
@@ -3130,9 +3033,9 @@
       }
     },
     "node_modules/@tiptap/extension-italic": {
-      "version": "2.0.0-beta.26",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-2.0.0-beta.26.tgz",
-      "integrity": "sha512-vejGe2ra4K5ipFOn1U9viqF9X9nPTX8WSJpSOux+9UbKjHpANy7bz69tp66OIi/Wh5L/MMDc+luH/04qfVnpZw==",
+      "version": "2.0.0-beta.28",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-2.0.0-beta.28.tgz",
+      "integrity": "sha512-/pKRiCfewh7nqiXRD3N4hQHfGrGNOiWPFYZfY35bSpvTms7PDb/MF7xT1CWW23hSpY31BBS+R/a66vlR/gqu7Q==",
       "funding": {
         "type": "github",
         "url": "https://github.com/sponsors/ueberdosis"
@@ -3142,9 +3045,9 @@
       }
     },
     "node_modules/@tiptap/extension-list-item": {
-      "version": "2.0.0-beta.20",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-2.0.0-beta.20.tgz",
-      "integrity": "sha512-5IPEspJt38t9ROj4xLUesOVEYlTT/R9Skd9meHRxJQZX1qrzBICs5PC/WRIsnexrvTBhdxpYgCYjpvpsJBlKuQ==",
+      "version": "2.0.0-beta.23",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-2.0.0-beta.23.tgz",
+      "integrity": "sha512-AkzvdELz3ZnrlZM0r9+ritBDOnAjXHR/8zCZhW0ZlWx4zyKPMsNG5ygivY+xr4QT65NEGRT8P8b2zOhXrMjjMQ==",
       "funding": {
         "type": "github",
         "url": "https://github.com/sponsors/ueberdosis"
@@ -3154,9 +3057,9 @@
       }
     },
     "node_modules/@tiptap/extension-ordered-list": {
-      "version": "2.0.0-beta.27",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-2.0.0-beta.27.tgz",
-      "integrity": "sha512-apFDeignxdZb3cA3p1HJu0zw1JgJdBYUBz1r7f99qdNybYuk3I/1MPUvlOuOgvIrBB/wydoyVDP+v9F7QN3tfQ==",
+      "version": "2.0.0-beta.30",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-2.0.0-beta.30.tgz",
+      "integrity": "sha512-GRxGQdq1u0Rp5N8TjthCqoZ//460m343A0HCN7UwfQOnX7Ipv0UJemwNkSHWrl7Pexym9vy3yPWgrn7oRRmgEw==",
       "funding": {
         "type": "github",
         "url": "https://github.com/sponsors/ueberdosis"
@@ -3166,9 +3069,9 @@
       }
     },
     "node_modules/@tiptap/extension-paragraph": {
-      "version": "2.0.0-beta.23",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-2.0.0-beta.23.tgz",
-      "integrity": "sha512-VWAxyzecErYWk97Kv/Gkghh97zAQTcaVOisEnYYArZAlyYDaYM48qVssAC/vnRRynP2eQxb1EkppbAxE+bMHAA==",
+      "version": "2.0.0-beta.26",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-2.0.0-beta.26.tgz",
+      "integrity": "sha512-WcYsuUa7LLfk0vi7I1dVjdMRu53B52FMMqd+UL1qPdDKVkU3DBsZVwPj+yyfQyqN8Mc/xyg9VacGaiKFLmWNDg==",
       "funding": {
         "type": "github",
         "url": "https://github.com/sponsors/ueberdosis"
@@ -3178,9 +3081,9 @@
       }
     },
     "node_modules/@tiptap/extension-strike": {
-      "version": "2.0.0-beta.27",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-2.0.0-beta.27.tgz",
-      "integrity": "sha512-2dmCgtesuDdivM/54Q+Y6Tc3JbGz1SkHP6c62piuqBiYLWg3xa16zChZOhfN8szbbQlBgLT6XRTDt3c2Ux+Dug==",
+      "version": "2.0.0-beta.29",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-2.0.0-beta.29.tgz",
+      "integrity": "sha512-zqFuY7GfNmZ/KClt6kxQ+msGo3syqucP/Xnlihxi+/h/G+oTvEwyOIXCtDOltvxcsWH/TUsdr5vzLp0j+Mdc6Q==",
       "funding": {
         "type": "github",
         "url": "https://github.com/sponsors/ueberdosis"
@@ -3190,9 +3093,9 @@
       }
     },
     "node_modules/@tiptap/extension-subscript": {
-      "version": "2.0.0-beta.10",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-subscript/-/extension-subscript-2.0.0-beta.10.tgz",
-      "integrity": "sha512-er8/1lp0Rb+SKwEioW0w4oVf3EkdQZ0WS/5kPBG4W0DncfUMT+bw5de76S3kRL9PLZ9UShAL7wuXtuiSi5QsMw==",
+      "version": "2.0.0-beta.13",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-subscript/-/extension-subscript-2.0.0-beta.13.tgz",
+      "integrity": "sha512-L9f2zKzNI5y4YvMdNxHDT4Y+8gS1UwtbTJ1vUJdCZGfF8DrMuTZIRp3LjOxYXydr7NGEXyYbucdm97Tzrsp8WA==",
       "funding": {
         "type": "github",
         "url": "https://github.com/sponsors/ueberdosis"
@@ -3202,9 +3105,9 @@
       }
     },
     "node_modules/@tiptap/extension-superscript": {
-      "version": "2.0.0-beta.10",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-superscript/-/extension-superscript-2.0.0-beta.10.tgz",
-      "integrity": "sha512-TUUBS8XsD2MorGORYVlhGDH7wcc9diSbHscD4Dnz8pKWVR0JPUd/od4h5qSffDzAOKxtphTiX9LOFWk6zVooKg==",
+      "version": "2.0.0-beta.13",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-superscript/-/extension-superscript-2.0.0-beta.13.tgz",
+      "integrity": "sha512-Vr9KIG2c4jzymcMMQCjhx2gppmRvnbw6Xvrd8YCpK4szyYI1ClMQ5KQMYl2zV3Y4ZIsivRSy9cE0ipGsXGE3Gw==",
       "funding": {
         "type": "github",
         "url": "https://github.com/sponsors/ueberdosis"
@@ -3214,9 +3117,9 @@
       }
     },
     "node_modules/@tiptap/extension-text": {
-      "version": "2.0.0-beta.15",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-2.0.0-beta.15.tgz",
-      "integrity": "sha512-S3j2+HyV2gsXZP8Wg/HA+YVXQsZ3nrXgBM9HmGAxB0ESOO50l7LWfip0f3qcw1oRlh5H3iLPkA6/f7clD2/TFA==",
+      "version": "2.0.0-beta.17",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-2.0.0-beta.17.tgz",
+      "integrity": "sha512-OyKL+pqWJEtjyd9/mrsuY1kZh2b3LWpOQDWKtd4aWR4EA0efmQG+7FPwcIeAVEh7ZoqM+/ABCnPjN6IjzIrSfg==",
       "funding": {
         "type": "github",
         "url": "https://github.com/sponsors/ueberdosis"
@@ -3226,9 +3129,9 @@
       }
     },
     "node_modules/@tiptap/extension-text-align": {
-      "version": "2.0.0-beta.29",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-text-align/-/extension-text-align-2.0.0-beta.29.tgz",
-      "integrity": "sha512-FNGpl0tVtgG7AK9kVWF/+CGYHta05NpoME4/j6+vhNlZLBNXRA+AKg7W5T8UxmtaC9yGoJsBs2X8M9eCxWVaEQ==",
+      "version": "2.0.0-beta.31",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-text-align/-/extension-text-align-2.0.0-beta.31.tgz",
+      "integrity": "sha512-gSJqi57piiMPc2r6WEkXv7ZgQIogigsRUhmlnZC/7s3zzOvjXrexWnV0Ctt/9A7BKcM7OHMykpZyoewvk6QRTw==",
       "funding": {
         "type": "github",
         "url": "https://github.com/sponsors/ueberdosis"
@@ -3238,9 +3141,9 @@
       }
     },
     "node_modules/@tiptap/extension-text-style": {
-      "version": "2.0.0-beta.23",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-text-style/-/extension-text-style-2.0.0-beta.23.tgz",
-      "integrity": "sha512-h/7o//RB4WRrLKWV7E5eFk7tZnfjH0Wt9klixOmvTmus6dm00a7r6wTuaT1GNjfPOgClP3K185lTA5rrdgrxRA==",
+      "version": "2.0.0-beta.26",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-text-style/-/extension-text-style-2.0.0-beta.26.tgz",
+      "integrity": "sha512-sHUlj5j86W53jvj9ijhXGyqxDdT2c9B7lVwdmDtksvSIrRYuCFqn7hFBzlypNBb56zePqBlIFymUmhK283L6fQ==",
       "funding": {
         "type": "github",
         "url": "https://github.com/sponsors/ueberdosis"
@@ -3250,9 +3153,9 @@
       }
     },
     "node_modules/@tiptap/extension-underline": {
-      "version": "2.0.0-beta.23",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-2.0.0-beta.23.tgz",
-      "integrity": "sha512-pMjFH/NpFWLd2XQQa5rG9rGVQ9mu3ygdtu6VGfJ3aAjzBiyLXDKhE4biIFWyFsr8zLpp7DjwbrmLV0UGvbG1WQ==",
+      "version": "2.0.0-beta.25",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-2.0.0-beta.25.tgz",
+      "integrity": "sha512-kRDdb/mF6QWzFGV3cQuLh6xyXULXaKPL/TghefoOZhwkdIWV/M3zFar5tsZO54+tbIrzxoVP6t7mO2Y5G/SLDQ==",
       "funding": {
         "type": "github",
         "url": "https://github.com/sponsors/ueberdosis"
@@ -3261,36 +3164,6 @@
         "@tiptap/core": "^2.0.0-beta.1"
       }
     },
-    "node_modules/@tiptap/starter-kit": {
-      "version": "2.0.0-beta.184",
-      "resolved": "https://registry.npmjs.org/@tiptap/starter-kit/-/starter-kit-2.0.0-beta.184.tgz",
-      "integrity": "sha512-FgF94i5RQzXiGAIkaubnXEaYwJfiZRbMPZcmarwNo8IyqPnLT34Q1yjw/qZ3nv7rDehWV5l/zenbrrNtPYVCkA==",
-      "dependencies": {
-        "@tiptap/core": "^2.0.0-beta.175",
-        "@tiptap/extension-blockquote": "^2.0.0-beta.26",
-        "@tiptap/extension-bold": "^2.0.0-beta.26",
-        "@tiptap/extension-bullet-list": "^2.0.0-beta.26",
-        "@tiptap/extension-code": "^2.0.0-beta.26",
-        "@tiptap/extension-code-block": "^2.0.0-beta.37",
-        "@tiptap/extension-document": "^2.0.0-beta.15",
-        "@tiptap/extension-dropcursor": "^2.0.0-beta.25",
-        "@tiptap/extension-gapcursor": "^2.0.0-beta.34",
-        "@tiptap/extension-hard-break": "^2.0.0-beta.30",
-        "@tiptap/extension-heading": "^2.0.0-beta.26",
-        "@tiptap/extension-history": "^2.0.0-beta.21",
-        "@tiptap/extension-horizontal-rule": "^2.0.0-beta.31",
-        "@tiptap/extension-italic": "^2.0.0-beta.26",
-        "@tiptap/extension-list-item": "^2.0.0-beta.20",
-        "@tiptap/extension-ordered-list": "^2.0.0-beta.27",
-        "@tiptap/extension-paragraph": "^2.0.0-beta.23",
-        "@tiptap/extension-strike": "^2.0.0-beta.27",
-        "@tiptap/extension-text": "^2.0.0-beta.15"
-      },
-      "funding": {
-        "type": "github",
-        "url": "https://github.com/sponsors/ueberdosis"
-      }
-    },
     "node_modules/@tootallnate/once": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
@@ -3447,7 +3320,8 @@
       "version": "0.0.29",
       "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
       "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "node_modules/@types/lodash": {
       "version": "4.14.182",
@@ -3473,7 +3347,8 @@
     "node_modules/@types/orderedmap": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/@types/orderedmap/-/orderedmap-1.0.0.tgz",
-      "integrity": "sha512-dxKo80TqYx3YtBipHwA/SdFmMMyLCnP+5mkEqN0eMjcTBzHkiiX0ES118DsjDBjvD+zeSsSU9jULTZ+frog+Gw=="
+      "integrity": "sha512-dxKo80TqYx3YtBipHwA/SdFmMMyLCnP+5mkEqN0eMjcTBzHkiiX0ES118DsjDBjvD+zeSsSU9jULTZ+frog+Gw==",
+      "peer": true
     },
     "node_modules/@types/parse-json": {
       "version": "4.0.0",
@@ -3481,75 +3356,20 @@
       "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
       "dev": true
     },
-    "node_modules/@types/prosemirror-commands": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/@types/prosemirror-commands/-/prosemirror-commands-1.0.4.tgz",
-      "integrity": "sha512-utDNYB3EXLjAfYIcRWJe6pn3kcQ5kG4RijbT/0Y/TFOm6yhvYS/D9eJVnijdg9LDjykapcezchxGRqFD5LcyaQ==",
-      "dependencies": {
-        "@types/prosemirror-model": "*",
-        "@types/prosemirror-state": "*",
-        "@types/prosemirror-view": "*"
-      }
-    },
-    "node_modules/@types/prosemirror-dropcursor": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/@types/prosemirror-dropcursor/-/prosemirror-dropcursor-1.0.3.tgz",
-      "integrity": "sha512-b0/8njnJ4lwyHKcGuCMf3x7r1KjxyugB1R/c2iMCjplsJHSC7UY9+OysqgJR5uUXRekUSGniiLgBtac/lvH6wg==",
-      "dependencies": {
-        "@types/prosemirror-state": "*"
-      }
-    },
-    "node_modules/@types/prosemirror-gapcursor": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/@types/prosemirror-gapcursor/-/prosemirror-gapcursor-1.0.4.tgz",
-      "integrity": "sha512-9xKjFIG5947dzerFvkLWp6F53JwrUYoYwh3SgcTFEp8SbSfNNrez/PFYVZKPnoqPoaK5WtTdQTaMwpCV9rXQIg==",
-      "dependencies": {
-        "@types/prosemirror-model": "*",
-        "@types/prosemirror-state": "*"
-      }
-    },
-    "node_modules/@types/prosemirror-history": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/@types/prosemirror-history/-/prosemirror-history-1.0.3.tgz",
-      "integrity": "sha512-5TloMDRavgLjOAKXp1Li8u0xcsspzbT1Cm9F2pwHOkgvQOz1jWQb2VIXO7RVNsFjLBZdIXlyfSLivro3DuMWXg==",
-      "dependencies": {
-        "@types/prosemirror-model": "*",
-        "@types/prosemirror-state": "*"
-      }
-    },
-    "node_modules/@types/prosemirror-keymap": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/@types/prosemirror-keymap/-/prosemirror-keymap-1.0.4.tgz",
-      "integrity": "sha512-ycevwkqUh+jEQtPwqO7sWGcm+Sybmhu8MpBsM8DlO3+YTKnXbKA6SDz/+q14q1wK3UA8lHJyfR+v+GPxfUSemg==",
-      "dependencies": {
-        "@types/prosemirror-commands": "*",
-        "@types/prosemirror-model": "*",
-        "@types/prosemirror-state": "*",
-        "@types/prosemirror-view": "*"
-      }
-    },
     "node_modules/@types/prosemirror-model": {
       "version": "1.16.2",
       "resolved": "https://registry.npmjs.org/@types/prosemirror-model/-/prosemirror-model-1.16.2.tgz",
       "integrity": "sha512-1XPJopkKP3oHSBP61uuSuW13DIDZPWvAzP6Pv2/6mixk8EBPUeRGIW548DjJTicMo23gEg1zvCZy9asblQdWag==",
+      "peer": true,
       "dependencies": {
         "@types/orderedmap": "*"
       }
     },
-    "node_modules/@types/prosemirror-schema-list": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/@types/prosemirror-schema-list/-/prosemirror-schema-list-1.0.3.tgz",
-      "integrity": "sha512-uWybOf+M2Ea7rlbs0yLsS4YJYNGXYtn4N+w8HCw3Vvfl6wBAROzlMt0gV/D/VW/7J/LlAjwMezuGe8xi24HzXA==",
-      "dependencies": {
-        "@types/orderedmap": "*",
-        "@types/prosemirror-model": "*",
-        "@types/prosemirror-state": "*"
-      }
-    },
     "node_modules/@types/prosemirror-state": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/@types/prosemirror-state/-/prosemirror-state-1.3.0.tgz",
       "integrity": "sha512-nMdUF6w8B++NH4V54X+4GvDty7M02UfuHQW0s1AS25Z4ZrOW4RSY2+s57doXBbeMSjzYV/QoMxCY2sT3KQ2VdQ==",
+      "peer": true,
       "dependencies": {
         "@types/prosemirror-model": "*",
         "@types/prosemirror-transform": "*",
@@ -3560,6 +3380,7 @@
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/@types/prosemirror-transform/-/prosemirror-transform-1.4.0.tgz",
       "integrity": "sha512-ntfuTl9nJWHvFykCmqJj4YQMws6G5H9nBaxHW0xRqfTxDxUvX2bCloqRN7bQTWg9h3VSP2lx45UuET1fn/oQ9Q==",
+      "peer": true,
       "dependencies": {
         "@types/prosemirror-model": "*"
       }
@@ -3568,6 +3389,7 @@
       "version": "1.23.3",
       "resolved": "https://registry.npmjs.org/@types/prosemirror-view/-/prosemirror-view-1.23.3.tgz",
       "integrity": "sha512-T5dPDmZiXAazJVSvnx55D6h4mcpiH2q2wTyO9zIeOdox5zx964+zcDl9dFNaXG3qCGlERwMPckhBZL1HCxyygw==",
+      "peer": true,
       "dependencies": {
         "@types/prosemirror-model": "*",
         "@types/prosemirror-state": "*",
@@ -3630,19 +3452,20 @@
       }
     },
     "node_modules/@typescript-eslint/eslint-plugin": {
-      "version": "5.23.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.23.0.tgz",
-      "integrity": "sha512-hEcSmG4XodSLiAp1uxv/OQSGsDY6QN3TcRU32gANp+19wGE1QQZLRS8/GV58VRUoXhnkuJ3ZxNQ3T6Z6zM59DA==",
+      "version": "5.31.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.31.0.tgz",
+      "integrity": "sha512-VKW4JPHzG5yhYQrQ1AzXgVgX8ZAJEvCz0QI6mLRX4tf7rnFfh5D8SKm0Pq6w5PyNfAWJk6sv313+nEt3ohWMBQ==",
       "dev": true,
+      "peer": true,
       "dependencies": {
-        "@typescript-eslint/scope-manager": "5.23.0",
-        "@typescript-eslint/type-utils": "5.23.0",
-        "@typescript-eslint/utils": "5.23.0",
-        "debug": "^4.3.2",
+        "@typescript-eslint/scope-manager": "5.31.0",
+        "@typescript-eslint/type-utils": "5.31.0",
+        "@typescript-eslint/utils": "5.31.0",
+        "debug": "^4.3.4",
         "functional-red-black-tree": "^1.0.1",
-        "ignore": "^5.1.8",
+        "ignore": "^5.2.0",
         "regexpp": "^3.2.0",
-        "semver": "^7.3.5",
+        "semver": "^7.3.7",
         "tsutils": "^3.21.0"
       },
       "engines": {
@@ -3662,16 +3485,51 @@
         }
       }
     },
+    "node_modules/@typescript-eslint/eslint-plugin/node_modules/debug": {
+      "version": "4.3.4",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+      "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ms": "2.1.2"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": {
+      "version": "7.3.7",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
+      "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
     "node_modules/@typescript-eslint/parser": {
-      "version": "5.23.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.23.0.tgz",
-      "integrity": "sha512-V06cYUkqcGqpFjb8ttVgzNF53tgbB/KoQT/iB++DOIExKmzI9vBJKjZKt/6FuV9c+zrDsvJKbJ2DOCYwX91cbw==",
+      "version": "5.31.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.31.0.tgz",
+      "integrity": "sha512-UStjQiZ9OFTFReTrN+iGrC6O/ko9LVDhreEK5S3edmXgR396JGq7CoX2TWIptqt/ESzU2iRKXAHfSF2WJFcWHw==",
       "dev": true,
+      "peer": true,
       "dependencies": {
-        "@typescript-eslint/scope-manager": "5.23.0",
-        "@typescript-eslint/types": "5.23.0",
-        "@typescript-eslint/typescript-estree": "5.23.0",
-        "debug": "^4.3.2"
+        "@typescript-eslint/scope-manager": "5.31.0",
+        "@typescript-eslint/types": "5.31.0",
+        "@typescript-eslint/typescript-estree": "5.31.0",
+        "debug": "^4.3.4"
       },
       "engines": {
         "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -3689,14 +3547,33 @@
         }
       }
     },
+    "node_modules/@typescript-eslint/parser/node_modules/debug": {
+      "version": "4.3.4",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+      "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ms": "2.1.2"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/@typescript-eslint/scope-manager": {
-      "version": "5.23.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.23.0.tgz",
-      "integrity": "sha512-EhjaFELQHCRb5wTwlGsNMvzK9b8Oco4aYNleeDlNuL6qXWDF47ch4EhVNPh8Rdhf9tmqbN4sWDk/8g+Z/J8JVw==",
+      "version": "5.31.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.31.0.tgz",
+      "integrity": "sha512-8jfEzBYDBG88rcXFxajdVavGxb5/XKXyvWgvD8Qix3EEJLCFIdVloJw+r9ww0wbyNLOTYyBsR+4ALNGdlalLLg==",
       "dev": true,
+      "peer": true,
       "dependencies": {
-        "@typescript-eslint/types": "5.23.0",
-        "@typescript-eslint/visitor-keys": "5.23.0"
+        "@typescript-eslint/types": "5.31.0",
+        "@typescript-eslint/visitor-keys": "5.31.0"
       },
       "engines": {
         "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -3707,13 +3584,14 @@
       }
     },
     "node_modules/@typescript-eslint/type-utils": {
-      "version": "5.23.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.23.0.tgz",
-      "integrity": "sha512-iuI05JsJl/SUnOTXA9f4oI+/4qS/Zcgk+s2ir+lRmXI+80D8GaGwoUqs4p+X+4AxDolPpEpVUdlEH4ADxFy4gw==",
+      "version": "5.31.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.31.0.tgz",
+      "integrity": "sha512-7ZYqFbvEvYXFn9ax02GsPcEOmuWNg+14HIf4q+oUuLnMbpJ6eHAivCg7tZMVwzrIuzX3QCeAOqKoyMZCv5xe+w==",
       "dev": true,
+      "peer": true,
       "dependencies": {
-        "@typescript-eslint/utils": "5.23.0",
-        "debug": "^4.3.2",
+        "@typescript-eslint/utils": "5.31.0",
+        "debug": "^4.3.4",
         "tsutils": "^3.21.0"
       },
       "engines": {
@@ -3732,11 +3610,30 @@
         }
       }
     },
+    "node_modules/@typescript-eslint/type-utils/node_modules/debug": {
+      "version": "4.3.4",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+      "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ms": "2.1.2"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/@typescript-eslint/types": {
-      "version": "5.23.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.23.0.tgz",
-      "integrity": "sha512-NfBsV/h4dir/8mJwdZz7JFibaKC3E/QdeMEDJhiAE3/eMkoniZ7MjbEMCGXw6MZnZDMN3G9S0mH/6WUIj91dmw==",
+      "version": "5.31.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.31.0.tgz",
+      "integrity": "sha512-/f/rMaEseux+I4wmR6mfpM2wvtNZb1p9hAV77hWfuKc3pmaANp5dLAZSiE3/8oXTYTt3uV9KW5yZKJsMievp6g==",
       "dev": true,
+      "peer": true,
       "engines": {
         "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
       },
@@ -3746,17 +3643,18 @@
       }
     },
     "node_modules/@typescript-eslint/typescript-estree": {
-      "version": "5.23.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.23.0.tgz",
-      "integrity": "sha512-xE9e0lrHhI647SlGMl+m+3E3CKPF1wzvvOEWnuE3CCjjT7UiRnDGJxmAcVKJIlFgK6DY9RB98eLr1OPigPEOGg==",
+      "version": "5.31.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.31.0.tgz",
+      "integrity": "sha512-3S625TMcARX71wBc2qubHaoUwMEn+l9TCsaIzYI/ET31Xm2c9YQ+zhGgpydjorwQO9pLfR/6peTzS/0G3J/hDw==",
       "dev": true,
+      "peer": true,
       "dependencies": {
-        "@typescript-eslint/types": "5.23.0",
-        "@typescript-eslint/visitor-keys": "5.23.0",
-        "debug": "^4.3.2",
-        "globby": "^11.0.4",
+        "@typescript-eslint/types": "5.31.0",
+        "@typescript-eslint/visitor-keys": "5.31.0",
+        "debug": "^4.3.4",
+        "globby": "^11.1.0",
         "is-glob": "^4.0.3",
-        "semver": "^7.3.5",
+        "semver": "^7.3.7",
         "tsutils": "^3.21.0"
       },
       "engines": {
@@ -3772,16 +3670,51 @@
         }
       }
     },
+    "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": {
+      "version": "4.3.4",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+      "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "ms": "2.1.2"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
+      "version": "7.3.7",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
+      "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
+      "dev": true,
+      "peer": true,
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
     "node_modules/@typescript-eslint/utils": {
-      "version": "5.23.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.23.0.tgz",
-      "integrity": "sha512-dbgaKN21drqpkbbedGMNPCtRPZo1IOUr5EI9Jrrh99r5UW5Q0dz46RKXeSBoPV+56R6dFKpbrdhgUNSJsDDRZA==",
+      "version": "5.31.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.31.0.tgz",
+      "integrity": "sha512-kcVPdQS6VIpVTQ7QnGNKMFtdJdvnStkqS5LeALr4rcwx11G6OWb2HB17NMPnlRHvaZP38hL9iK8DdE9Fne7NYg==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "@types/json-schema": "^7.0.9",
-        "@typescript-eslint/scope-manager": "5.23.0",
-        "@typescript-eslint/types": "5.23.0",
-        "@typescript-eslint/typescript-estree": "5.23.0",
+        "@typescript-eslint/scope-manager": "5.31.0",
+        "@typescript-eslint/types": "5.31.0",
+        "@typescript-eslint/typescript-estree": "5.31.0",
         "eslint-scope": "^5.1.1",
         "eslint-utils": "^3.0.0"
       },
@@ -3797,13 +3730,14 @@
       }
     },
     "node_modules/@typescript-eslint/visitor-keys": {
-      "version": "5.23.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.23.0.tgz",
-      "integrity": "sha512-Vd4mFNchU62sJB8pX19ZSPog05B0Y0CE2UxAZPT5k4iqhRYjPnqyY3woMxCd0++t9OTqkgjST+1ydLBi7e2Fvg==",
+      "version": "5.31.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.31.0.tgz",
+      "integrity": "sha512-ZK0jVxSjS4gnPirpVjXHz7mgdOsZUHzNYSfTw2yPa3agfbt9YfqaBiBZFSSxeBWnpWkzCxTfUpnzA3Vily/CSg==",
       "dev": true,
+      "peer": true,
       "dependencies": {
-        "@typescript-eslint/types": "5.23.0",
-        "eslint-visitor-keys": "^3.0.0"
+        "@typescript-eslint/types": "5.31.0",
+        "eslint-visitor-keys": "^3.3.0"
       },
       "engines": {
         "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
@@ -4036,6 +3970,7 @@
       "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
       "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
       "dev": true,
+      "peer": true,
       "peerDependencies": {
         "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
       }
@@ -4280,6 +4215,7 @@
       "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz",
       "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "call-bind": "^1.0.2",
         "define-properties": "^1.1.4",
@@ -4315,6 +4251,7 @@
       "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz",
       "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "call-bind": "^1.0.2",
         "define-properties": "^1.1.3",
@@ -5320,7 +5257,8 @@
       "version": "1.0.11",
       "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz",
       "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "node_modules/connect": {
       "version": "3.7.0",
@@ -5944,7 +5882,8 @@
       "version": "0.1.4",
       "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
       "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "node_modules/default-gateway": {
       "version": "6.0.3",
@@ -6212,6 +6151,7 @@
       "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
       "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "esutils": "^2.0.2"
       },
@@ -6515,6 +6455,7 @@
       "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.0.tgz",
       "integrity": "sha512-URbD8tgRthKD3YcC39vbvSDrX23upXnPcnGAjQfgxXF5ID75YcENawc9ZX/9iTP9ptUyfCLIxTTuMYoRfiOVKA==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "call-bind": "^1.0.2",
         "es-to-primitive": "^1.2.1",
@@ -6558,6 +6499,7 @@
       "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz",
       "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "has": "^1.0.3"
       }
@@ -6567,6 +6509,7 @@
       "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
       "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "is-callable": "^1.1.4",
         "is-date-object": "^1.0.1",
@@ -6958,12 +6901,13 @@
       }
     },
     "node_modules/eslint": {
-      "version": "8.15.0",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.15.0.tgz",
-      "integrity": "sha512-GG5USZ1jhCu8HJkzGgeK8/+RGnHaNYZGrGDzUtigK3BsGESW/rs2az23XqE0WVwDxy1VRvvjSSGu5nB0Bu+6SA==",
+      "version": "8.20.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.20.0.tgz",
+      "integrity": "sha512-d4ixhz5SKCa1D6SCPrivP7yYVi7nyD6A4vs6HIAul9ujBzcEmZVM3/0NN/yu5nKhmO1wjp5xQ46iRfmDGlOviA==",
       "dev": true,
+      "peer": true,
       "dependencies": {
-        "@eslint/eslintrc": "^1.2.3",
+        "@eslint/eslintrc": "^1.3.0",
         "@humanwhocodes/config-array": "^0.9.2",
         "ajv": "^6.10.0",
         "chalk": "^4.0.0",
@@ -6981,7 +6925,7 @@
         "file-entry-cache": "^6.0.1",
         "functional-red-black-tree": "^1.0.1",
         "glob-parent": "^6.0.1",
-        "globals": "^13.6.0",
+        "globals": "^13.15.0",
         "ignore": "^5.2.0",
         "import-fresh": "^3.0.0",
         "imurmurhash": "^0.1.4",
@@ -7014,6 +6958,7 @@
       "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz",
       "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "confusing-browser-globals": "^1.0.10",
         "object.assign": "^4.1.2",
@@ -7033,6 +6978,7 @@
       "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
       "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
       "dev": true,
+      "peer": true,
       "bin": {
         "semver": "bin/semver.js"
       }
@@ -7042,6 +6988,7 @@
       "resolved": "https://registry.npmjs.org/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-17.0.0.tgz",
       "integrity": "sha512-elNiuzD0kPAPTXjFWg+lE24nMdHMtuxgYoD30OyMD6yrW1AhFZPAg27VX7d3tzOErw+dgJTNWfRSDqEcXb4V0g==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "eslint-config-airbnb-base": "^15.0.0"
       },
@@ -7057,6 +7004,7 @@
       "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz",
       "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "debug": "^3.2.7",
         "resolve": "^1.20.0"
@@ -7067,6 +7015,7 @@
       "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
       "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "ms": "^2.1.1"
       }
@@ -7076,6 +7025,7 @@
       "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz",
       "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "debug": "^3.2.7",
         "find-up": "^2.1.0"
@@ -7089,6 +7039,7 @@
       "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
       "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "ms": "^2.1.1"
       }
@@ -7098,6 +7049,7 @@
       "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
       "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "locate-path": "^2.0.0"
       },
@@ -7110,6 +7062,7 @@
       "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
       "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "p-locate": "^2.0.0",
         "path-exists": "^3.0.0"
@@ -7123,6 +7076,7 @@
       "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
       "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "p-try": "^1.0.0"
       },
@@ -7135,6 +7089,7 @@
       "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
       "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "p-limit": "^1.1.0"
       },
@@ -7147,6 +7102,7 @@
       "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
       "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=",
       "dev": true,
+      "peer": true,
       "engines": {
         "node": ">=4"
       }
@@ -7156,6 +7112,7 @@
       "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
       "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
       "dev": true,
+      "peer": true,
       "engines": {
         "node": ">=4"
       }
@@ -7165,6 +7122,7 @@
       "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz",
       "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "array-includes": "^3.1.4",
         "array.prototype.flat": "^1.2.5",
@@ -7192,6 +7150,7 @@
       "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
       "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "ms": "2.0.0"
       }
@@ -7201,6 +7160,7 @@
       "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
       "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "esutils": "^2.0.2"
       },
@@ -7213,6 +7173,7 @@
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
       "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "brace-expansion": "^1.1.7"
       },
@@ -7224,7 +7185,8 @@
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
       "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "node_modules/eslint-scope": {
       "version": "5.1.1",
@@ -7244,6 +7206,7 @@
       "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
       "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "eslint-visitor-keys": "^2.0.0"
       },
@@ -7262,6 +7225,7 @@
       "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
       "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
       "dev": true,
+      "peer": true,
       "engines": {
         "node": ">=10"
       }
@@ -7271,6 +7235,7 @@
       "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
       "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
       "dev": true,
+      "peer": true,
       "engines": {
         "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
       }
@@ -7280,6 +7245,7 @@
       "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
       "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "fast-deep-equal": "^3.1.1",
         "fast-json-stable-stringify": "^2.0.0",
@@ -7296,6 +7262,7 @@
       "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
       "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "color-convert": "^2.0.1"
       },
@@ -7310,13 +7277,15 @@
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
       "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "node_modules/eslint/node_modules/chalk": {
       "version": "4.1.2",
       "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
       "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "ansi-styles": "^4.1.0",
         "supports-color": "^7.1.0"
@@ -7333,6 +7302,7 @@
       "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
       "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "color-name": "~1.1.4"
       },
@@ -7344,13 +7314,15 @@
       "version": "1.1.4",
       "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
       "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "node_modules/eslint/node_modules/escape-string-regexp": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
       "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
       "dev": true,
+      "peer": true,
       "engines": {
         "node": ">=10"
       },
@@ -7363,6 +7335,7 @@
       "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
       "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "esrecurse": "^4.3.0",
         "estraverse": "^5.2.0"
@@ -7376,6 +7349,7 @@
       "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
       "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
       "dev": true,
+      "peer": true,
       "engines": {
         "node": ">=4.0"
       }
@@ -7385,6 +7359,7 @@
       "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
       "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "is-glob": "^4.0.3"
       },
@@ -7397,6 +7372,7 @@
       "resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz",
       "integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "type-fest": "^0.20.2"
       },
@@ -7412,6 +7388,7 @@
       "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
       "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
       "dev": true,
+      "peer": true,
       "engines": {
         "node": ">=8"
       }
@@ -7421,6 +7398,7 @@
       "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
       "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "argparse": "^2.0.1"
       },
@@ -7432,13 +7410,15 @@
       "version": "0.4.1",
       "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
       "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "node_modules/eslint/node_modules/minimatch": {
       "version": "3.1.2",
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
       "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "brace-expansion": "^1.1.7"
       },
@@ -7451,6 +7431,7 @@
       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
       "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "has-flag": "^4.0.0"
       },
@@ -7463,6 +7444,7 @@
       "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
       "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
       "dev": true,
+      "peer": true,
       "engines": {
         "node": ">=10"
       },
@@ -7483,6 +7465,7 @@
       "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz",
       "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "acorn": "^8.7.1",
         "acorn-jsx": "^5.3.2",
@@ -7510,6 +7493,7 @@
       "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
       "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "estraverse": "^5.1.0"
       },
@@ -7522,6 +7506,7 @@
       "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
       "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
       "dev": true,
+      "peer": true,
       "engines": {
         "node": ">=4.0"
       }
@@ -7786,7 +7771,8 @@
       "version": "2.0.6",
       "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
       "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "node_modules/fastq": {
       "version": "1.13.0",
@@ -7828,6 +7814,7 @@
       "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
       "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "flat-cache": "^3.0.4"
       },
@@ -7954,6 +7941,7 @@
       "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
       "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "flatted": "^3.1.0",
         "rimraf": "^3.0.2"
@@ -8084,6 +8072,7 @@
       "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz",
       "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "call-bind": "^1.0.2",
         "define-properties": "^1.1.3",
@@ -8101,7 +8090,8 @@
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
       "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "node_modules/functions-have-names": {
       "version": "1.2.3",
@@ -8205,6 +8195,7 @@
       "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz",
       "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "call-bind": "^1.0.2",
         "get-intrinsic": "^1.1.1"
@@ -8314,6 +8305,7 @@
       "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
       "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==",
       "dev": true,
+      "peer": true,
       "funding": {
         "url": "https://github.com/sponsors/ljharb"
       }
@@ -8852,6 +8844,7 @@
       "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz",
       "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "get-intrinsic": "^1.1.0",
         "has": "^1.0.3",
@@ -8927,6 +8920,7 @@
       "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
       "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "has-bigints": "^1.0.1"
       },
@@ -8951,6 +8945,7 @@
       "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
       "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "call-bind": "^1.0.2",
         "has-tostringtag": "^1.0.0"
@@ -8967,6 +8962,7 @@
       "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz",
       "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==",
       "dev": true,
+      "peer": true,
       "engines": {
         "node": ">= 0.4"
       },
@@ -9094,6 +9090,7 @@
       "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz",
       "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==",
       "dev": true,
+      "peer": true,
       "engines": {
         "node": ">= 0.4"
       },
@@ -9114,6 +9111,7 @@
       "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
       "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "has-tostringtag": "^1.0.0"
       },
@@ -9199,6 +9197,7 @@
       "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz",
       "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "call-bind": "^1.0.2"
       },
@@ -9222,6 +9221,7 @@
       "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
       "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "has-tostringtag": "^1.0.0"
       },
@@ -9237,6 +9237,7 @@
       "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
       "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "has-symbols": "^1.0.2"
       },
@@ -9269,6 +9270,7 @@
       "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
       "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "call-bind": "^1.0.2"
       },
@@ -9534,7 +9536,8 @@
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
       "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "node_modules/json5": {
       "version": "2.2.1",
@@ -9954,6 +9957,7 @@
       "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
       "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "prelude-ls": "^1.2.1",
         "type-check": "~0.4.0"
@@ -10067,7 +10071,8 @@
       "version": "4.6.2",
       "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
       "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "node_modules/lodash.once": {
       "version": "4.1.1",
@@ -10659,7 +10664,8 @@
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
       "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "node_modules/needle": {
       "version": "2.9.1",
@@ -10714,22 +10720,22 @@
       }
     },
     "node_modules/ngx-tiptap": {
-      "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/ngx-tiptap/-/ngx-tiptap-3.0.4.tgz",
-      "integrity": "sha512-iU69pGqYoan5v9N8l92tpFSncB7x5mbXcJVwJwUDtEI922N+59cd4pw5y+NrN3er9E/HVAgOLfRB40TDHliwqQ==",
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/ngx-tiptap/-/ngx-tiptap-5.0.0.tgz",
+      "integrity": "sha512-SlySnakZ7OroJSG5owPqVQ1ncqS9tgWYQ7551aI2VzZmcdCKKss00cdy+TqNyeRUg0b1+9Ep+yorUmg2CHPKLg==",
       "dependencies": {
-        "tslib": "^2.2.0"
+        "tslib": "^2.3.0"
       },
       "peerDependencies": {
-        "@angular/common": ">=12.0.0",
-        "@angular/core": ">=12.0.0",
-        "@angular/forms": ">=12.0.0",
-        "@tiptap/core": "^2.0.0-beta.113",
-        "@tiptap/extension-bubble-menu": "^2.0.0-beta.36",
-        "@tiptap/extension-floating-menu": "^2.0.0-beta.30",
-        "@types/prosemirror-model": "^1.13.2",
-        "@types/prosemirror-state": "^1.2.7",
-        "@types/prosemirror-view": "^1.19.1"
+        "@angular/common": ">=13.0.0",
+        "@angular/core": ">=13.0.0",
+        "@angular/forms": ">=13.0.0",
+        "@tiptap/core": "^2.0.0-beta.162",
+        "@tiptap/extension-bubble-menu": "^2.0.0-beta.54",
+        "@tiptap/extension-floating-menu": "^2.0.0-beta.49",
+        "@types/prosemirror-model": "^1.16.0",
+        "@types/prosemirror-state": "^1.2.8",
+        "@types/prosemirror-view": "^1.23.0"
       }
     },
     "node_modules/ngx-translate-testing": {
@@ -11251,6 +11257,7 @@
       "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz",
       "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "call-bind": "^1.0.2",
         "define-properties": "^1.1.3",
@@ -11265,6 +11272,7 @@
       "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz",
       "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "call-bind": "^1.0.2",
         "define-properties": "^1.1.3",
@@ -11348,6 +11356,7 @@
       "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
       "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "deep-is": "^0.1.3",
         "fast-levenshtein": "^2.0.6",
@@ -11454,9 +11463,9 @@
       }
     },
     "node_modules/orderedmap": {
-      "version": "1.1.7",
-      "resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-1.1.7.tgz",
-      "integrity": "sha512-B1SuadDDwIRXXutaJQ1xjreGL3hxujpexBG4PquoXbgJD8bjp2k8b8qI/mk7q0LUdIx7T8IALWB8mPbfsjbGCw=="
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-2.0.0.tgz",
+      "integrity": "sha512-buf4PoAMlh45b8a8gsGy/X6w279TSqkyAS0C0wdTSJwFSU+ljQFJON5I8NfjLHoCXwpSROIo2wr0g33T+kQshQ=="
     },
     "node_modules/os-family": {
       "version": "1.1.0",
@@ -12471,6 +12480,7 @@
       "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
       "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
       "dev": true,
+      "peer": true,
       "engines": {
         "node": ">= 0.8.0"
       }
@@ -12528,93 +12538,63 @@
       }
     },
     "node_modules/prosemirror-commands": {
-      "version": "1.2.2",
-      "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.2.2.tgz",
-      "integrity": "sha512-TX+KpWudMon06frryfpO/u7hsQv2hu8L4VSVbCpi3/7wXHBgl+35mV85qfa3RpT8xD2f3MdeoTqH0vy5JdbXPg==",
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.3.0.tgz",
+      "integrity": "sha512-BwBbZ5OAScPcm0x7H8SPbqjuEJnCU2RJT9LDyOiiIl/3NbL1nJZI4SFNHwU2e/tRr2Xe7JsptpzseqvZvToLBQ==",
       "dependencies": {
         "prosemirror-model": "^1.0.0",
         "prosemirror-state": "^1.0.0",
         "prosemirror-transform": "^1.0.0"
       }
     },
-    "node_modules/prosemirror-dropcursor": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/prosemirror-dropcursor/-/prosemirror-dropcursor-1.4.0.tgz",
-      "integrity": "sha512-6+YwTjmqDwlA/Dm+5wK67ezgqgjA/MhSDgaNxKUzH97SmeuWFXyLeDRxxOPZeSo7yTxcDGUCWTEjmQZsVBuMrQ==",
-      "dependencies": {
-        "prosemirror-state": "^1.0.0",
-        "prosemirror-transform": "^1.1.0",
-        "prosemirror-view": "^1.1.0"
-      }
-    },
-    "node_modules/prosemirror-gapcursor": {
-      "version": "1.2.2",
-      "resolved": "https://registry.npmjs.org/prosemirror-gapcursor/-/prosemirror-gapcursor-1.2.2.tgz",
-      "integrity": "sha512-7YzuRBbu9W7HGQde84kCHfIjaRLNcAdeijbgqrm/R9dsdTWkV+rrdcmic/sCc+bptiNpvjCEE+R6hrbT8zFQeQ==",
-      "dependencies": {
-        "prosemirror-keymap": "^1.0.0",
-        "prosemirror-model": "^1.0.0",
-        "prosemirror-state": "^1.0.0",
-        "prosemirror-view": "^1.0.0"
-      }
-    },
-    "node_modules/prosemirror-history": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.2.0.tgz",
-      "integrity": "sha512-B9v9xtf4fYbKxQwIr+3wtTDNLDZcmMMmGiI3TAPShnUzvo+Rmv1GiUrsQChY1meetHl7rhML2cppF3FTs7f7UQ==",
-      "dependencies": {
-        "prosemirror-state": "^1.2.2",
-        "prosemirror-transform": "^1.0.0",
-        "rope-sequence": "^1.3.0"
-      }
-    },
     "node_modules/prosemirror-keymap": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.1.5.tgz",
-      "integrity": "sha512-8SZgPH3K+GLsHL2wKuwBD9rxhsbnVBTwpHCO4VUO5GmqUQlxd/2GtBVWTsyLq4Dp3N9nGgPd3+lZFKUDuVp+Vw==",
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.2.0.tgz",
+      "integrity": "sha512-TdSfu+YyLDd54ufN/ZeD1VtBRYpgZnTPnnbY+4R08DDgs84KrIPEPbJL8t1Lm2dkljFx6xeBE26YWH3aIzkPKg==",
       "dependencies": {
         "prosemirror-state": "^1.0.0",
         "w3c-keyname": "^2.2.0"
       }
     },
     "node_modules/prosemirror-model": {
-      "version": "1.16.1",
-      "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.16.1.tgz",
-      "integrity": "sha512-r1/w0HDU40TtkXp0DyKBnFPYwd8FSlUSJmGCGFv4DeynfeSlyQF2FD0RQbVEMOe6P3PpUSXM6LZBV7W/YNZ4mA==",
+      "version": "1.18.1",
+      "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.18.1.tgz",
+      "integrity": "sha512-IxSVBKAEMjD7s3n8cgtwMlxAXZrC7Mlag7zYsAKDndAqnDScvSmp/UdnRTV/B33lTCVU3CCm7dyAn/rVVD0mcw==",
       "dependencies": {
-        "orderedmap": "^1.1.0"
+        "orderedmap": "^2.0.0"
       }
     },
     "node_modules/prosemirror-schema-list": {
-      "version": "1.1.6",
-      "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.1.6.tgz",
-      "integrity": "sha512-aFGEdaCWmJzouZ8DwedmvSsL50JpRkqhQ6tcpThwJONVVmCgI36LJHtoQ4VGZbusMavaBhXXr33zyD2IVsTlkw==",
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.2.0.tgz",
+      "integrity": "sha512-8PT/9xOx1HHdC7fDNNfhQ50Z8Mzu7nKyA1KCDltSpcZVZIbB0k7KtsHrnXyuIhbLlScoymBiLZ00c5MH6wdFsA==",
       "dependencies": {
         "prosemirror-model": "^1.0.0",
+        "prosemirror-state": "^1.0.0",
         "prosemirror-transform": "^1.0.0"
       }
     },
     "node_modules/prosemirror-state": {
-      "version": "1.3.4",
-      "resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.3.4.tgz",
-      "integrity": "sha512-Xkkrpd1y/TQ6HKzN3agsQIGRcLckUMA9u3j207L04mt8ToRgpGeyhbVv0HI7omDORIBHjR29b7AwlATFFf2GLA==",
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.1.tgz",
+      "integrity": "sha512-U/LBDW2gNmVa07sz/D229XigSdDQ5CLFwVB1Vb32MJbAHHhWe/6pOc721faI17tqw4pZ49i1xfY/jEZ9tbIhPg==",
       "dependencies": {
         "prosemirror-model": "^1.0.0",
         "prosemirror-transform": "^1.0.0"
       }
     },
     "node_modules/prosemirror-transform": {
-      "version": "1.4.2",
-      "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.4.2.tgz",
-      "integrity": "sha512-bcIsf3uRZhfab0xRfyyxOEh6eqSszq/hJbDbmUumFnbHBoWhB/uXbpz6vvUxfk0XiEvrZDJ+5pXRrNDc1Hu3vQ==",
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.6.0.tgz",
+      "integrity": "sha512-MAp7AjsjEGEqQY0sSMufNIUuEyB1ZR9Fqlm8dTwwWwpEJRv/plsKjWXBbx52q3Ml8MtaMcd7ic14zAHVB3WaMw==",
       "dependencies": {
         "prosemirror-model": "^1.0.0"
       }
     },
     "node_modules/prosemirror-view": {
-      "version": "1.23.13",
-      "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.23.13.tgz",
-      "integrity": "sha512-X/NcwZv8pgcEWfs3n++Wz4nDgqDIeDvJ9kfCk6DCoC9XUlDekqJLFt9wCcCUBXedb8hs/dmd+JmcaLgbr67XZw==",
+      "version": "1.26.2",
+      "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.26.2.tgz",
+      "integrity": "sha512-CGKw+GadkfSBEwRAJTHCEKJ4DlV6/3IhAdjpwGyZHUHtbP7jX4Ol4zmi7xa2c6GOabDlIJLYXJydoNYLX7lNeQ==",
       "dependencies": {
         "prosemirror-model": "^1.16.0",
         "prosemirror-state": "^1.0.0",
@@ -12875,6 +12855,7 @@
       "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
       "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
       "dev": true,
+      "peer": true,
       "engines": {
         "node": ">=8"
       },
@@ -13110,11 +13091,6 @@
         "url": "https://github.com/sponsors/isaacs"
       }
     },
-    "node_modules/rope-sequence": {
-      "version": "1.3.3",
-      "resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.3.tgz",
-      "integrity": "sha512-85aZYCxweiD5J8yTEbw+E6A27zSnLPNDL0WfPdw3YYodq7WjnTKo0q4dtyQ2gz23iPT8Q9CUyJtAaUNcTxRf5Q=="
-    },
     "node_modules/run-async": {
       "version": "2.4.1",
       "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
@@ -13858,6 +13834,7 @@
       "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz",
       "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "call-bind": "^1.0.2",
         "define-properties": "^1.1.4",
@@ -13872,6 +13849,7 @@
       "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz",
       "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "call-bind": "^1.0.2",
         "define-properties": "^1.1.4",
@@ -13917,6 +13895,7 @@
       "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
       "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
       "dev": true,
+      "peer": true,
       "engines": {
         "node": ">=8"
       },
@@ -14864,6 +14843,7 @@
       "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz",
       "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "@types/json5": "^0.0.29",
         "json5": "^1.0.1",
@@ -14876,6 +14856,7 @@
       "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
       "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "minimist": "^1.2.0"
       },
@@ -14888,6 +14869,7 @@
       "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
       "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
       "dev": true,
+      "peer": true,
       "engines": {
         "node": ">=4"
       }
@@ -14902,6 +14884,7 @@
       "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
       "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "tslib": "^1.8.1"
       },
@@ -14916,7 +14899,8 @@
       "version": "1.14.1",
       "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
       "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "node_modules/tunnel-agent": {
       "version": "0.6.0",
@@ -14934,6 +14918,7 @@
       "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
       "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "prelude-ls": "^1.2.1"
       },
@@ -15017,6 +15002,7 @@
       "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
       "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "call-bind": "^1.0.2",
         "has-bigints": "^1.0.2",
@@ -15150,7 +15136,8 @@
       "version": "2.3.0",
       "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
       "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "node_modules/validate-npm-package-name": {
       "version": "3.0.0",
@@ -15180,9 +15167,9 @@
       }
     },
     "node_modules/w3c-keyname": {
-      "version": "2.2.4",
-      "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.4.tgz",
-      "integrity": "sha512-tOhfEwEzFLJzf6d1ZPkYfGj+FWhIpBux9ppoP3rlclw3Z0BZv3N7b7030Z1kYth+6rDuAsXUFr+d0VE6Ed1ikw=="
+      "version": "2.2.5",
+      "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.5.tgz",
+      "integrity": "sha512-WJrK7i6w+ULuZsGscCezbCH4Aev5U3xY87vnSimzzEgPQhb0Sa0a1rE3c2jtEwrFtSfi61Jefw3jI5/DD/3jbQ=="
     },
     "node_modules/watchpack": {
       "version": "2.3.1",
@@ -15608,6 +15595,7 @@
       "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
       "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
       "dev": true,
+      "peer": true,
       "dependencies": {
         "is-bigint": "^1.0.1",
         "is-boolean-object": "^1.1.0",
@@ -15679,6 +15667,7 @@
       "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
       "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
       "dev": true,
+      "peer": true,
       "engines": {
         "node": ">=0.10.0"
       }
@@ -17444,15 +17433,16 @@
       "dev": true
     },
     "@eslint/eslintrc": {
-      "version": "1.2.3",
-      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.3.tgz",
-      "integrity": "sha512-uGo44hIwoLGNyduRpjdEpovcbMdd+Nv7amtmJxnKmI8xj6yd5LncmSwDa5NgX/41lIFJtkjD6YdVfgEzPfJ5UA==",
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz",
+      "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==",
       "dev": true,
+      "peer": true,
       "requires": {
         "ajv": "^6.12.4",
         "debug": "^4.3.2",
         "espree": "^9.3.2",
-        "globals": "^13.9.0",
+        "globals": "^13.15.0",
         "ignore": "^5.2.0",
         "import-fresh": "^3.2.1",
         "js-yaml": "^4.1.0",
@@ -17465,6 +17455,7 @@
           "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
           "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
           "dev": true,
+          "peer": true,
           "requires": {
             "fast-deep-equal": "^3.1.1",
             "fast-json-stable-stringify": "^2.0.0",
@@ -17476,13 +17467,15 @@
           "version": "2.0.1",
           "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
           "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
-          "dev": true
+          "dev": true,
+          "peer": true
         },
         "globals": {
-          "version": "13.15.0",
-          "resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz",
-          "integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==",
+          "version": "13.17.0",
+          "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz",
+          "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==",
           "dev": true,
+          "peer": true,
           "requires": {
             "type-fest": "^0.20.2"
           }
@@ -17492,6 +17485,7 @@
           "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
           "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
           "dev": true,
+          "peer": true,
           "requires": {
             "argparse": "^2.0.1"
           }
@@ -17500,13 +17494,15 @@
           "version": "0.4.1",
           "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
           "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
-          "dev": true
+          "dev": true,
+          "peer": true
         },
         "minimatch": {
           "version": "3.1.2",
           "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
           "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
           "dev": true,
+          "peer": true,
           "requires": {
             "brace-expansion": "^1.1.7"
           }
@@ -17515,7 +17511,8 @@
           "version": "0.20.2",
           "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
           "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
-          "dev": true
+          "dev": true,
+          "peer": true
         }
       }
     },
@@ -17530,6 +17527,7 @@
       "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz",
       "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==",
       "dev": true,
+      "peer": true,
       "requires": {
         "@humanwhocodes/object-schema": "^1.2.1",
         "debug": "^4.1.1",
@@ -17540,20 +17538,15 @@
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
       "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "@iqb/eslint-config": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/@iqb/eslint-config/-/eslint-config-1.1.1.tgz",
-      "integrity": "sha512-KaAdhBSnCXXfxeQRI51tZxgW58FXkAvHSFvZE38b+gvKPZ5YVYXuX0dlEEu7rYezeW7jCOk6zRtdkUbB5DJVyg==",
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/@iqb/eslint-config/-/eslint-config-2.1.1.tgz",
+      "integrity": "sha512-F94TVoZ0xT4mvxKdr9efDiRG74M0TQERCH2Eh4AL1u1JseDqYwbNhcnItadvdjho9USt9sMLDdxwOnADfHkE1g==",
       "dev": true,
-      "requires": {
-        "@typescript-eslint/eslint-plugin": "^5.19.0",
-        "@typescript-eslint/parser": "^5.19.0",
-        "eslint": "^8.13.0",
-        "eslint-config-airbnb-typescript": "^17.0.0",
-        "eslint-plugin-import": "^2.26.0"
-      }
+      "requires": {}
     },
     "@istanbuljs/load-nyc-config": {
       "version": "1.1.0",
@@ -17750,247 +17743,159 @@
       }
     },
     "@tiptap/core": {
-      "version": "2.0.0-beta.175",
-      "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.0.0-beta.175.tgz",
-      "integrity": "sha512-dDf+2GtifskNLysn49kaCIz0o5hf6VDZ8J7jSQAfoPDEkEkfw9OKhWrR7NzWW6J34CSJreFDRiWkGt8Qz283Vg==",
+      "version": "2.0.0-beta.182",
+      "resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.0.0-beta.182.tgz",
+      "integrity": "sha512-MZGkMGnVnWhBzjvpBNwQ9zBz38ndi3Irbf90uCTSArR0kaCVkW4vmyuPuOXd+0SO8Yv/l5oyDdOCpaG3rnQYfw==",
       "requires": {
-        "@types/prosemirror-commands": "^1.0.4",
-        "@types/prosemirror-keymap": "^1.0.4",
-        "@types/prosemirror-model": "^1.16.0",
-        "@types/prosemirror-schema-list": "^1.0.3",
-        "@types/prosemirror-state": "^1.2.8",
-        "@types/prosemirror-transform": "^1.1.5",
-        "@types/prosemirror-view": "^1.23.1",
-        "prosemirror-commands": "^1.2.1",
-        "prosemirror-keymap": "^1.1.5",
-        "prosemirror-model": "^1.16.1",
-        "prosemirror-schema-list": "^1.1.6",
-        "prosemirror-state": "^1.3.4",
-        "prosemirror-transform": "^1.3.3",
-        "prosemirror-view": "^1.23.6"
+        "prosemirror-commands": "1.3.0",
+        "prosemirror-keymap": "1.2.0",
+        "prosemirror-model": "1.18.1",
+        "prosemirror-schema-list": "1.2.0",
+        "prosemirror-state": "1.4.1",
+        "prosemirror-transform": "1.6.0",
+        "prosemirror-view": "1.26.2"
       }
     },
     "@tiptap/extension-blockquote": {
-      "version": "2.0.0-beta.26",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-2.0.0-beta.26.tgz",
-      "integrity": "sha512-A6yjcYovONJfOjQFk6vDYXswaCdCtCwjL7w9VTB0R2DLTuJvvRt9DWN0IDcMrj5G+aMgDq4GUUTitv+2Y8krDg==",
+      "version": "2.0.0-beta.29",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-blockquote/-/extension-blockquote-2.0.0-beta.29.tgz",
+      "integrity": "sha512-zMYT5TtpKWav9VhTn4JLyMvXmhEdbD6on0MdhcTjRm0I5ugyR4ZbJwh2aelM7G9DZVYzB8jZU18OSDJmo7Af7w==",
       "requires": {}
     },
     "@tiptap/extension-bold": {
-      "version": "2.0.0-beta.26",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-2.0.0-beta.26.tgz",
-      "integrity": "sha512-pnO0I5sEQM3pmowjMGQ74adLzvc6HqGyLyqMizaGMicPu9uTYlSdId+qckYEEgPwPMaEShtv2Vg+ZHs7KVqfcg==",
+      "version": "2.0.0-beta.28",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-bold/-/extension-bold-2.0.0-beta.28.tgz",
+      "integrity": "sha512-DY8GOzw9xjmTFrnvTbgHUNxTnDfKrkDgrhe0SUvdkT2udntWp8umPdhPiD3vczLgHOJw6tX68qMRjbsR1ZPcHQ==",
       "requires": {}
     },
     "@tiptap/extension-bubble-menu": {
-      "version": "2.0.0-beta.56",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.0.0-beta.56.tgz",
-      "integrity": "sha512-nZozwauICdaNPmDPrSn1JFd/9/2rLtK8i2vBOcqxWHObVROvu8ZlJspnrJv23vS6P7/ZO3e/QLVHpnn+1yVq3g==",
+      "version": "2.0.0-beta.61",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.0.0-beta.61.tgz",
+      "integrity": "sha512-T3Yx+y1sUnXAJjK1CUfsQewSxOpDca9KzKqN2H9c9RZ9UlorR9XmZg6YYW7m9a7adeihj+o3cCO9jRd8dV+nnA==",
       "requires": {
-        "prosemirror-state": "^1.3.4",
-        "prosemirror-view": "^1.23.6",
+        "prosemirror-state": "1.4.1",
+        "prosemirror-view": "1.26.2",
         "tippy.js": "^6.3.7"
       }
     },
     "@tiptap/extension-bullet-list": {
-      "version": "2.0.0-beta.26",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-2.0.0-beta.26.tgz",
-      "integrity": "sha512-1n5HV8gY1tLjPk4x48nva6SZlFHoPlRfF6pqSu9JcJxPO7FUSPxUokuz4swYNe0LRrtykfyNz44dUcxKVhoFow==",
-      "requires": {}
-    },
-    "@tiptap/extension-code": {
-      "version": "2.0.0-beta.26",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-code/-/extension-code-2.0.0-beta.26.tgz",
-      "integrity": "sha512-QcFWdEFfbJ1n5UFFBD17QPPAJ3J5p/b7XV484u0shCzywO7aNPV32QeHy1z0eMoyZtCbOWf6hg/a7Ugv8IwpHw==",
+      "version": "2.0.0-beta.29",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-bullet-list/-/extension-bullet-list-2.0.0-beta.29.tgz",
+      "integrity": "sha512-R8VB2l1ZB6VeGWx/t/04nBS5Wg3qjIDEZCpPihj2fccJOw99Lu0Ub2UJg/SfdGmeNNpBh4ZYYFv1g/XjyzlXKg==",
       "requires": {}
     },
-    "@tiptap/extension-code-block": {
-      "version": "2.0.0-beta.37",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-code-block/-/extension-code-block-2.0.0-beta.37.tgz",
-      "integrity": "sha512-mJAM+PHaNoKRYwM3D36lZ51/aoPxxvZNQn3UBnZ6G7l0ZJSgB3JvBEzqK6S8nNFeYIIxGwv4QF6vXe4MG9ie2g==",
-      "requires": {
-        "prosemirror-state": "^1.3.4"
-      }
-    },
     "@tiptap/extension-color": {
-      "version": "2.0.0-beta.9",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-color/-/extension-color-2.0.0-beta.9.tgz",
-      "integrity": "sha512-c8zcaNCdwUwbgrutfsG7LD9KH7ZvDVwKOZHbOL4gMSwdH9s+6r1ThRFLEbKgHIJlTa2jd96qoo+lVfj1Qwp7ww==",
+      "version": "2.0.0-beta.12",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-color/-/extension-color-2.0.0-beta.12.tgz",
+      "integrity": "sha512-ddFIUdb7e0gLlYlcQiyZ+zRC4nXtpX2bhOHZ7IdCasoHYEWs/8dsncngLtymAgsRBeruMZ5K6ZhAYtgQVUugqQ==",
       "requires": {}
     },
     "@tiptap/extension-document": {
-      "version": "2.0.0-beta.15",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-2.0.0-beta.15.tgz",
-      "integrity": "sha512-ypENC+xUYD5m2t+KOKNYqyXnanXd5fxyIyhR1qeEEwwQwMXGNrO3kCH6O4mIDCpy+/WqHvVay2tV5dVsXnvY8w==",
+      "version": "2.0.0-beta.17",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-2.0.0-beta.17.tgz",
+      "integrity": "sha512-L6sg0FNchbtIpQkCSjMmItVGs3/vep8Fq56WRtDc1wBSGUSmtHaxQG7F2FZLnNIUMuvzVMRD81m2vYG73WkY6A==",
       "requires": {}
     },
-    "@tiptap/extension-dropcursor": {
-      "version": "2.0.0-beta.25",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-dropcursor/-/extension-dropcursor-2.0.0-beta.25.tgz",
-      "integrity": "sha512-GYf5s6dkZtsDy+TEkrQK6kLbfbitG4qnk02D+FlhlJMI/Nnx8rYCRJbwEHDdqrfX7XwZzULMqqqHvzxZYrEeNg==",
-      "requires": {
-        "@types/prosemirror-dropcursor": "^1.0.3",
-        "prosemirror-dropcursor": "^1.4.0"
-      }
-    },
     "@tiptap/extension-floating-menu": {
-      "version": "2.0.0-beta.51",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-2.0.0-beta.51.tgz",
-      "integrity": "sha512-rEe7jADK9xr2n2LJsrGEN3Dz7sEGC1JT/7AdTdaZBxQRQvwxTjomqYGrt+LnX+v0MYggh6swMzj7upJosnKbBg==",
+      "version": "2.0.0-beta.56",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-floating-menu/-/extension-floating-menu-2.0.0-beta.56.tgz",
+      "integrity": "sha512-j/evHE/6UPGkIgXny9IGcAh0IrcnQmg0b2NBYebs2mqx9xYKYoe+0jVgNdLp/0M3MRgQCzyWTyatBDBFOUR2mw==",
       "requires": {
-        "prosemirror-state": "^1.3.4",
-        "prosemirror-view": "^1.23.6",
+        "prosemirror-state": "1.4.1",
+        "prosemirror-view": "1.26.2",
         "tippy.js": "^6.3.7"
       }
     },
     "@tiptap/extension-font-family": {
-      "version": "2.0.0-beta.21",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-font-family/-/extension-font-family-2.0.0-beta.21.tgz",
-      "integrity": "sha512-5KVCtuEBf1QyZxs/IOL0CPDtB5X3rk8QdDB8fB+UlASa6c/Dq59Uo2aObGOgAWNDdY0Vd9MmuDTvnJKP2LI2Ng==",
-      "requires": {}
-    },
-    "@tiptap/extension-gapcursor": {
-      "version": "2.0.0-beta.34",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-gapcursor/-/extension-gapcursor-2.0.0-beta.34.tgz",
-      "integrity": "sha512-Vm8vMWWQ2kJcUOLfB5CEo5pYgyudI7JeeiZvX9ScPmUmgKVYhEpt3EAICY9pUYJ41aAVH35gZLXkUtsz2f9GHw==",
-      "requires": {
-        "@types/prosemirror-gapcursor": "^1.0.4",
-        "prosemirror-gapcursor": "^1.2.1"
-      }
-    },
-    "@tiptap/extension-hard-break": {
-      "version": "2.0.0-beta.30",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-hard-break/-/extension-hard-break-2.0.0-beta.30.tgz",
-      "integrity": "sha512-X9xj/S+CikrbIE7ccUFVwit5QHEbflnKVxod+4zPwr1cxogFbE9AyLZE2MpYdx3z9LcnTYYi9leBqFrP4T/Olw==",
+      "version": "2.0.0-beta.24",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-font-family/-/extension-font-family-2.0.0-beta.24.tgz",
+      "integrity": "sha512-R7fgyJb4X6KS2Xcr73dYDxM1NSBNIQrtHLeSa3Cfc3Y9UDqeMFUIEgYUh4sBLBi3Z8Y9D3RRMvxN1x39j5eLLA==",
       "requires": {}
     },
     "@tiptap/extension-heading": {
-      "version": "2.0.0-beta.26",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-2.0.0-beta.26.tgz",
-      "integrity": "sha512-nR6W/3rjnZH1Swo7tGBoYsmO6xMvu9MGq6jlm3WVHCB7B3CsrRvCkTwGjVIbKTaZC4bQfx5gvAUpQFvwuU+M5w==",
+      "version": "2.0.0-beta.29",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-heading/-/extension-heading-2.0.0-beta.29.tgz",
+      "integrity": "sha512-q92jYcsT5bPhvuQaB0h44Z9r+Ii22tDYo082KMVnR4+tknHT/3xx+p4JC8KHjh+/5W8Quyafqy6mS8L8VX0zsQ==",
       "requires": {}
     },
     "@tiptap/extension-highlight": {
-      "version": "2.0.0-beta.33",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-highlight/-/extension-highlight-2.0.0-beta.33.tgz",
-      "integrity": "sha512-TXyMiCcY5a0w5UFax350xU+T79GKJw2XwJ6Punc6sY2RRRgKaEbN1ZF0JCdQhQvD1ooKImHzCRYR8Pldb0xgfg==",
+      "version": "2.0.0-beta.35",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-highlight/-/extension-highlight-2.0.0-beta.35.tgz",
+      "integrity": "sha512-xvEKOyuTj4mhQ8GIOItaSymJhGkWt2gGuCvmFWnTVZAaJJQOlgUTdkmayLCtwoDDP7biiuDhRJokTukGGmhUZw==",
       "requires": {}
     },
-    "@tiptap/extension-history": {
-      "version": "2.0.0-beta.21",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-history/-/extension-history-2.0.0-beta.21.tgz",
-      "integrity": "sha512-0v8Cl30V4dsabdpspLdk+f+lMoIvLFlJN5WRxtc7RRZ5gfJVxPHwooIKdvC51brfh/oJtWFCNMRjhoz0fRaF9A==",
-      "requires": {
-        "@types/prosemirror-history": "^1.0.3",
-        "prosemirror-history": "^1.2.0"
-      }
-    },
-    "@tiptap/extension-horizontal-rule": {
-      "version": "2.0.0-beta.31",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.0.0-beta.31.tgz",
-      "integrity": "sha512-MNc4retfjRgkv3qxqGya0+/BEd1Kmn+oMsCRvE+8x3sXyKIse+vdqMuG5qUcA6np0ZD/9hh1riiQ1GQdgc23Ng==",
-      "requires": {
-        "prosemirror-state": "^1.3.4"
-      }
-    },
     "@tiptap/extension-image": {
-      "version": "2.0.0-beta.27",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-image/-/extension-image-2.0.0-beta.27.tgz",
-      "integrity": "sha512-kdJ7V39yNdVWUco/RBe7WgvFevd81l+pU6+Je9HpelqBBP953wDttzLMuAWQB4AeLv9WhKSlORHiFv2SKsV5NA==",
+      "version": "2.0.0-beta.30",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-image/-/extension-image-2.0.0-beta.30.tgz",
+      "integrity": "sha512-VhEmgiKkZMiKR7hbpJgIlIUS/QNjSGI5ER7mKDAbuV1IB5yb6nGjZ6o3Exrr2/CaTaW5hQarBC1z2Xgdu05EGg==",
       "requires": {}
     },
     "@tiptap/extension-italic": {
-      "version": "2.0.0-beta.26",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-2.0.0-beta.26.tgz",
-      "integrity": "sha512-vejGe2ra4K5ipFOn1U9viqF9X9nPTX8WSJpSOux+9UbKjHpANy7bz69tp66OIi/Wh5L/MMDc+luH/04qfVnpZw==",
+      "version": "2.0.0-beta.28",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-italic/-/extension-italic-2.0.0-beta.28.tgz",
+      "integrity": "sha512-/pKRiCfewh7nqiXRD3N4hQHfGrGNOiWPFYZfY35bSpvTms7PDb/MF7xT1CWW23hSpY31BBS+R/a66vlR/gqu7Q==",
       "requires": {}
     },
     "@tiptap/extension-list-item": {
-      "version": "2.0.0-beta.20",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-2.0.0-beta.20.tgz",
-      "integrity": "sha512-5IPEspJt38t9ROj4xLUesOVEYlTT/R9Skd9meHRxJQZX1qrzBICs5PC/WRIsnexrvTBhdxpYgCYjpvpsJBlKuQ==",
+      "version": "2.0.0-beta.23",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-list-item/-/extension-list-item-2.0.0-beta.23.tgz",
+      "integrity": "sha512-AkzvdELz3ZnrlZM0r9+ritBDOnAjXHR/8zCZhW0ZlWx4zyKPMsNG5ygivY+xr4QT65NEGRT8P8b2zOhXrMjjMQ==",
       "requires": {}
     },
     "@tiptap/extension-ordered-list": {
-      "version": "2.0.0-beta.27",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-2.0.0-beta.27.tgz",
-      "integrity": "sha512-apFDeignxdZb3cA3p1HJu0zw1JgJdBYUBz1r7f99qdNybYuk3I/1MPUvlOuOgvIrBB/wydoyVDP+v9F7QN3tfQ==",
+      "version": "2.0.0-beta.30",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-ordered-list/-/extension-ordered-list-2.0.0-beta.30.tgz",
+      "integrity": "sha512-GRxGQdq1u0Rp5N8TjthCqoZ//460m343A0HCN7UwfQOnX7Ipv0UJemwNkSHWrl7Pexym9vy3yPWgrn7oRRmgEw==",
       "requires": {}
     },
     "@tiptap/extension-paragraph": {
-      "version": "2.0.0-beta.23",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-2.0.0-beta.23.tgz",
-      "integrity": "sha512-VWAxyzecErYWk97Kv/Gkghh97zAQTcaVOisEnYYArZAlyYDaYM48qVssAC/vnRRynP2eQxb1EkppbAxE+bMHAA==",
+      "version": "2.0.0-beta.26",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-paragraph/-/extension-paragraph-2.0.0-beta.26.tgz",
+      "integrity": "sha512-WcYsuUa7LLfk0vi7I1dVjdMRu53B52FMMqd+UL1qPdDKVkU3DBsZVwPj+yyfQyqN8Mc/xyg9VacGaiKFLmWNDg==",
       "requires": {}
     },
     "@tiptap/extension-strike": {
-      "version": "2.0.0-beta.27",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-2.0.0-beta.27.tgz",
-      "integrity": "sha512-2dmCgtesuDdivM/54Q+Y6Tc3JbGz1SkHP6c62piuqBiYLWg3xa16zChZOhfN8szbbQlBgLT6XRTDt3c2Ux+Dug==",
+      "version": "2.0.0-beta.29",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-strike/-/extension-strike-2.0.0-beta.29.tgz",
+      "integrity": "sha512-zqFuY7GfNmZ/KClt6kxQ+msGo3syqucP/Xnlihxi+/h/G+oTvEwyOIXCtDOltvxcsWH/TUsdr5vzLp0j+Mdc6Q==",
       "requires": {}
     },
     "@tiptap/extension-subscript": {
-      "version": "2.0.0-beta.10",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-subscript/-/extension-subscript-2.0.0-beta.10.tgz",
-      "integrity": "sha512-er8/1lp0Rb+SKwEioW0w4oVf3EkdQZ0WS/5kPBG4W0DncfUMT+bw5de76S3kRL9PLZ9UShAL7wuXtuiSi5QsMw==",
+      "version": "2.0.0-beta.13",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-subscript/-/extension-subscript-2.0.0-beta.13.tgz",
+      "integrity": "sha512-L9f2zKzNI5y4YvMdNxHDT4Y+8gS1UwtbTJ1vUJdCZGfF8DrMuTZIRp3LjOxYXydr7NGEXyYbucdm97Tzrsp8WA==",
       "requires": {}
     },
     "@tiptap/extension-superscript": {
-      "version": "2.0.0-beta.10",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-superscript/-/extension-superscript-2.0.0-beta.10.tgz",
-      "integrity": "sha512-TUUBS8XsD2MorGORYVlhGDH7wcc9diSbHscD4Dnz8pKWVR0JPUd/od4h5qSffDzAOKxtphTiX9LOFWk6zVooKg==",
+      "version": "2.0.0-beta.13",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-superscript/-/extension-superscript-2.0.0-beta.13.tgz",
+      "integrity": "sha512-Vr9KIG2c4jzymcMMQCjhx2gppmRvnbw6Xvrd8YCpK4szyYI1ClMQ5KQMYl2zV3Y4ZIsivRSy9cE0ipGsXGE3Gw==",
       "requires": {}
     },
     "@tiptap/extension-text": {
-      "version": "2.0.0-beta.15",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-2.0.0-beta.15.tgz",
-      "integrity": "sha512-S3j2+HyV2gsXZP8Wg/HA+YVXQsZ3nrXgBM9HmGAxB0ESOO50l7LWfip0f3qcw1oRlh5H3iLPkA6/f7clD2/TFA==",
+      "version": "2.0.0-beta.17",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-text/-/extension-text-2.0.0-beta.17.tgz",
+      "integrity": "sha512-OyKL+pqWJEtjyd9/mrsuY1kZh2b3LWpOQDWKtd4aWR4EA0efmQG+7FPwcIeAVEh7ZoqM+/ABCnPjN6IjzIrSfg==",
       "requires": {}
     },
     "@tiptap/extension-text-align": {
-      "version": "2.0.0-beta.29",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-text-align/-/extension-text-align-2.0.0-beta.29.tgz",
-      "integrity": "sha512-FNGpl0tVtgG7AK9kVWF/+CGYHta05NpoME4/j6+vhNlZLBNXRA+AKg7W5T8UxmtaC9yGoJsBs2X8M9eCxWVaEQ==",
+      "version": "2.0.0-beta.31",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-text-align/-/extension-text-align-2.0.0-beta.31.tgz",
+      "integrity": "sha512-gSJqi57piiMPc2r6WEkXv7ZgQIogigsRUhmlnZC/7s3zzOvjXrexWnV0Ctt/9A7BKcM7OHMykpZyoewvk6QRTw==",
       "requires": {}
     },
     "@tiptap/extension-text-style": {
-      "version": "2.0.0-beta.23",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-text-style/-/extension-text-style-2.0.0-beta.23.tgz",
-      "integrity": "sha512-h/7o//RB4WRrLKWV7E5eFk7tZnfjH0Wt9klixOmvTmus6dm00a7r6wTuaT1GNjfPOgClP3K185lTA5rrdgrxRA==",
+      "version": "2.0.0-beta.26",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-text-style/-/extension-text-style-2.0.0-beta.26.tgz",
+      "integrity": "sha512-sHUlj5j86W53jvj9ijhXGyqxDdT2c9B7lVwdmDtksvSIrRYuCFqn7hFBzlypNBb56zePqBlIFymUmhK283L6fQ==",
       "requires": {}
     },
     "@tiptap/extension-underline": {
-      "version": "2.0.0-beta.23",
-      "resolved": "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-2.0.0-beta.23.tgz",
-      "integrity": "sha512-pMjFH/NpFWLd2XQQa5rG9rGVQ9mu3ygdtu6VGfJ3aAjzBiyLXDKhE4biIFWyFsr8zLpp7DjwbrmLV0UGvbG1WQ==",
+      "version": "2.0.0-beta.25",
+      "resolved": "https://registry.npmjs.org/@tiptap/extension-underline/-/extension-underline-2.0.0-beta.25.tgz",
+      "integrity": "sha512-kRDdb/mF6QWzFGV3cQuLh6xyXULXaKPL/TghefoOZhwkdIWV/M3zFar5tsZO54+tbIrzxoVP6t7mO2Y5G/SLDQ==",
       "requires": {}
     },
-    "@tiptap/starter-kit": {
-      "version": "2.0.0-beta.184",
-      "resolved": "https://registry.npmjs.org/@tiptap/starter-kit/-/starter-kit-2.0.0-beta.184.tgz",
-      "integrity": "sha512-FgF94i5RQzXiGAIkaubnXEaYwJfiZRbMPZcmarwNo8IyqPnLT34Q1yjw/qZ3nv7rDehWV5l/zenbrrNtPYVCkA==",
-      "requires": {
-        "@tiptap/core": "^2.0.0-beta.175",
-        "@tiptap/extension-blockquote": "^2.0.0-beta.26",
-        "@tiptap/extension-bold": "^2.0.0-beta.26",
-        "@tiptap/extension-bullet-list": "^2.0.0-beta.26",
-        "@tiptap/extension-code": "^2.0.0-beta.26",
-        "@tiptap/extension-code-block": "^2.0.0-beta.37",
-        "@tiptap/extension-document": "^2.0.0-beta.15",
-        "@tiptap/extension-dropcursor": "^2.0.0-beta.25",
-        "@tiptap/extension-gapcursor": "^2.0.0-beta.34",
-        "@tiptap/extension-hard-break": "^2.0.0-beta.30",
-        "@tiptap/extension-heading": "^2.0.0-beta.26",
-        "@tiptap/extension-history": "^2.0.0-beta.21",
-        "@tiptap/extension-horizontal-rule": "^2.0.0-beta.31",
-        "@tiptap/extension-italic": "^2.0.0-beta.26",
-        "@tiptap/extension-list-item": "^2.0.0-beta.20",
-        "@tiptap/extension-ordered-list": "^2.0.0-beta.27",
-        "@tiptap/extension-paragraph": "^2.0.0-beta.23",
-        "@tiptap/extension-strike": "^2.0.0-beta.27",
-        "@tiptap/extension-text": "^2.0.0-beta.15"
-      }
-    },
     "@tootallnate/once": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
@@ -18143,7 +18048,8 @@
       "version": "0.0.29",
       "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
       "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "@types/lodash": {
       "version": "4.14.182",
@@ -18169,7 +18075,8 @@
     "@types/orderedmap": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/@types/orderedmap/-/orderedmap-1.0.0.tgz",
-      "integrity": "sha512-dxKo80TqYx3YtBipHwA/SdFmMMyLCnP+5mkEqN0eMjcTBzHkiiX0ES118DsjDBjvD+zeSsSU9jULTZ+frog+Gw=="
+      "integrity": "sha512-dxKo80TqYx3YtBipHwA/SdFmMMyLCnP+5mkEqN0eMjcTBzHkiiX0ES118DsjDBjvD+zeSsSU9jULTZ+frog+Gw==",
+      "peer": true
     },
     "@types/parse-json": {
       "version": "4.0.0",
@@ -18177,75 +18084,20 @@
       "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
       "dev": true
     },
-    "@types/prosemirror-commands": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/@types/prosemirror-commands/-/prosemirror-commands-1.0.4.tgz",
-      "integrity": "sha512-utDNYB3EXLjAfYIcRWJe6pn3kcQ5kG4RijbT/0Y/TFOm6yhvYS/D9eJVnijdg9LDjykapcezchxGRqFD5LcyaQ==",
-      "requires": {
-        "@types/prosemirror-model": "*",
-        "@types/prosemirror-state": "*",
-        "@types/prosemirror-view": "*"
-      }
-    },
-    "@types/prosemirror-dropcursor": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/@types/prosemirror-dropcursor/-/prosemirror-dropcursor-1.0.3.tgz",
-      "integrity": "sha512-b0/8njnJ4lwyHKcGuCMf3x7r1KjxyugB1R/c2iMCjplsJHSC7UY9+OysqgJR5uUXRekUSGniiLgBtac/lvH6wg==",
-      "requires": {
-        "@types/prosemirror-state": "*"
-      }
-    },
-    "@types/prosemirror-gapcursor": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/@types/prosemirror-gapcursor/-/prosemirror-gapcursor-1.0.4.tgz",
-      "integrity": "sha512-9xKjFIG5947dzerFvkLWp6F53JwrUYoYwh3SgcTFEp8SbSfNNrez/PFYVZKPnoqPoaK5WtTdQTaMwpCV9rXQIg==",
-      "requires": {
-        "@types/prosemirror-model": "*",
-        "@types/prosemirror-state": "*"
-      }
-    },
-    "@types/prosemirror-history": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/@types/prosemirror-history/-/prosemirror-history-1.0.3.tgz",
-      "integrity": "sha512-5TloMDRavgLjOAKXp1Li8u0xcsspzbT1Cm9F2pwHOkgvQOz1jWQb2VIXO7RVNsFjLBZdIXlyfSLivro3DuMWXg==",
-      "requires": {
-        "@types/prosemirror-model": "*",
-        "@types/prosemirror-state": "*"
-      }
-    },
-    "@types/prosemirror-keymap": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/@types/prosemirror-keymap/-/prosemirror-keymap-1.0.4.tgz",
-      "integrity": "sha512-ycevwkqUh+jEQtPwqO7sWGcm+Sybmhu8MpBsM8DlO3+YTKnXbKA6SDz/+q14q1wK3UA8lHJyfR+v+GPxfUSemg==",
-      "requires": {
-        "@types/prosemirror-commands": "*",
-        "@types/prosemirror-model": "*",
-        "@types/prosemirror-state": "*",
-        "@types/prosemirror-view": "*"
-      }
-    },
     "@types/prosemirror-model": {
       "version": "1.16.2",
       "resolved": "https://registry.npmjs.org/@types/prosemirror-model/-/prosemirror-model-1.16.2.tgz",
       "integrity": "sha512-1XPJopkKP3oHSBP61uuSuW13DIDZPWvAzP6Pv2/6mixk8EBPUeRGIW548DjJTicMo23gEg1zvCZy9asblQdWag==",
+      "peer": true,
       "requires": {
         "@types/orderedmap": "*"
       }
     },
-    "@types/prosemirror-schema-list": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/@types/prosemirror-schema-list/-/prosemirror-schema-list-1.0.3.tgz",
-      "integrity": "sha512-uWybOf+M2Ea7rlbs0yLsS4YJYNGXYtn4N+w8HCw3Vvfl6wBAROzlMt0gV/D/VW/7J/LlAjwMezuGe8xi24HzXA==",
-      "requires": {
-        "@types/orderedmap": "*",
-        "@types/prosemirror-model": "*",
-        "@types/prosemirror-state": "*"
-      }
-    },
     "@types/prosemirror-state": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/@types/prosemirror-state/-/prosemirror-state-1.3.0.tgz",
       "integrity": "sha512-nMdUF6w8B++NH4V54X+4GvDty7M02UfuHQW0s1AS25Z4ZrOW4RSY2+s57doXBbeMSjzYV/QoMxCY2sT3KQ2VdQ==",
+      "peer": true,
       "requires": {
         "@types/prosemirror-model": "*",
         "@types/prosemirror-transform": "*",
@@ -18256,6 +18108,7 @@
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/@types/prosemirror-transform/-/prosemirror-transform-1.4.0.tgz",
       "integrity": "sha512-ntfuTl9nJWHvFykCmqJj4YQMws6G5H9nBaxHW0xRqfTxDxUvX2bCloqRN7bQTWg9h3VSP2lx45UuET1fn/oQ9Q==",
+      "peer": true,
       "requires": {
         "@types/prosemirror-model": "*"
       }
@@ -18264,6 +18117,7 @@
       "version": "1.23.3",
       "resolved": "https://registry.npmjs.org/@types/prosemirror-view/-/prosemirror-view-1.23.3.tgz",
       "integrity": "sha512-T5dPDmZiXAazJVSvnx55D6h4mcpiH2q2wTyO9zIeOdox5zx964+zcDl9dFNaXG3qCGlERwMPckhBZL1HCxyygw==",
+      "peer": true,
       "requires": {
         "@types/prosemirror-model": "*",
         "@types/prosemirror-state": "*",
@@ -18326,98 +18180,174 @@
       }
     },
     "@typescript-eslint/eslint-plugin": {
-      "version": "5.23.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.23.0.tgz",
-      "integrity": "sha512-hEcSmG4XodSLiAp1uxv/OQSGsDY6QN3TcRU32gANp+19wGE1QQZLRS8/GV58VRUoXhnkuJ3ZxNQ3T6Z6zM59DA==",
+      "version": "5.31.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.31.0.tgz",
+      "integrity": "sha512-VKW4JPHzG5yhYQrQ1AzXgVgX8ZAJEvCz0QI6mLRX4tf7rnFfh5D8SKm0Pq6w5PyNfAWJk6sv313+nEt3ohWMBQ==",
       "dev": true,
+      "peer": true,
       "requires": {
-        "@typescript-eslint/scope-manager": "5.23.0",
-        "@typescript-eslint/type-utils": "5.23.0",
-        "@typescript-eslint/utils": "5.23.0",
-        "debug": "^4.3.2",
+        "@typescript-eslint/scope-manager": "5.31.0",
+        "@typescript-eslint/type-utils": "5.31.0",
+        "@typescript-eslint/utils": "5.31.0",
+        "debug": "^4.3.4",
         "functional-red-black-tree": "^1.0.1",
-        "ignore": "^5.1.8",
+        "ignore": "^5.2.0",
         "regexpp": "^3.2.0",
-        "semver": "^7.3.5",
+        "semver": "^7.3.7",
         "tsutils": "^3.21.0"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "4.3.4",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+          "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "ms": "2.1.2"
+          }
+        },
+        "semver": {
+          "version": "7.3.7",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
+          "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "lru-cache": "^6.0.0"
+          }
+        }
       }
     },
     "@typescript-eslint/parser": {
-      "version": "5.23.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.23.0.tgz",
-      "integrity": "sha512-V06cYUkqcGqpFjb8ttVgzNF53tgbB/KoQT/iB++DOIExKmzI9vBJKjZKt/6FuV9c+zrDsvJKbJ2DOCYwX91cbw==",
+      "version": "5.31.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.31.0.tgz",
+      "integrity": "sha512-UStjQiZ9OFTFReTrN+iGrC6O/ko9LVDhreEK5S3edmXgR396JGq7CoX2TWIptqt/ESzU2iRKXAHfSF2WJFcWHw==",
       "dev": true,
+      "peer": true,
       "requires": {
-        "@typescript-eslint/scope-manager": "5.23.0",
-        "@typescript-eslint/types": "5.23.0",
-        "@typescript-eslint/typescript-estree": "5.23.0",
-        "debug": "^4.3.2"
+        "@typescript-eslint/scope-manager": "5.31.0",
+        "@typescript-eslint/types": "5.31.0",
+        "@typescript-eslint/typescript-estree": "5.31.0",
+        "debug": "^4.3.4"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "4.3.4",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+          "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "ms": "2.1.2"
+          }
+        }
       }
     },
     "@typescript-eslint/scope-manager": {
-      "version": "5.23.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.23.0.tgz",
-      "integrity": "sha512-EhjaFELQHCRb5wTwlGsNMvzK9b8Oco4aYNleeDlNuL6qXWDF47ch4EhVNPh8Rdhf9tmqbN4sWDk/8g+Z/J8JVw==",
+      "version": "5.31.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.31.0.tgz",
+      "integrity": "sha512-8jfEzBYDBG88rcXFxajdVavGxb5/XKXyvWgvD8Qix3EEJLCFIdVloJw+r9ww0wbyNLOTYyBsR+4ALNGdlalLLg==",
       "dev": true,
+      "peer": true,
       "requires": {
-        "@typescript-eslint/types": "5.23.0",
-        "@typescript-eslint/visitor-keys": "5.23.0"
+        "@typescript-eslint/types": "5.31.0",
+        "@typescript-eslint/visitor-keys": "5.31.0"
       }
     },
     "@typescript-eslint/type-utils": {
-      "version": "5.23.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.23.0.tgz",
-      "integrity": "sha512-iuI05JsJl/SUnOTXA9f4oI+/4qS/Zcgk+s2ir+lRmXI+80D8GaGwoUqs4p+X+4AxDolPpEpVUdlEH4ADxFy4gw==",
+      "version": "5.31.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.31.0.tgz",
+      "integrity": "sha512-7ZYqFbvEvYXFn9ax02GsPcEOmuWNg+14HIf4q+oUuLnMbpJ6eHAivCg7tZMVwzrIuzX3QCeAOqKoyMZCv5xe+w==",
       "dev": true,
+      "peer": true,
       "requires": {
-        "@typescript-eslint/utils": "5.23.0",
-        "debug": "^4.3.2",
+        "@typescript-eslint/utils": "5.31.0",
+        "debug": "^4.3.4",
         "tsutils": "^3.21.0"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "4.3.4",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+          "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "ms": "2.1.2"
+          }
+        }
       }
     },
     "@typescript-eslint/types": {
-      "version": "5.23.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.23.0.tgz",
-      "integrity": "sha512-NfBsV/h4dir/8mJwdZz7JFibaKC3E/QdeMEDJhiAE3/eMkoniZ7MjbEMCGXw6MZnZDMN3G9S0mH/6WUIj91dmw==",
-      "dev": true
+      "version": "5.31.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.31.0.tgz",
+      "integrity": "sha512-/f/rMaEseux+I4wmR6mfpM2wvtNZb1p9hAV77hWfuKc3pmaANp5dLAZSiE3/8oXTYTt3uV9KW5yZKJsMievp6g==",
+      "dev": true,
+      "peer": true
     },
     "@typescript-eslint/typescript-estree": {
-      "version": "5.23.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.23.0.tgz",
-      "integrity": "sha512-xE9e0lrHhI647SlGMl+m+3E3CKPF1wzvvOEWnuE3CCjjT7UiRnDGJxmAcVKJIlFgK6DY9RB98eLr1OPigPEOGg==",
+      "version": "5.31.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.31.0.tgz",
+      "integrity": "sha512-3S625TMcARX71wBc2qubHaoUwMEn+l9TCsaIzYI/ET31Xm2c9YQ+zhGgpydjorwQO9pLfR/6peTzS/0G3J/hDw==",
       "dev": true,
+      "peer": true,
       "requires": {
-        "@typescript-eslint/types": "5.23.0",
-        "@typescript-eslint/visitor-keys": "5.23.0",
-        "debug": "^4.3.2",
-        "globby": "^11.0.4",
+        "@typescript-eslint/types": "5.31.0",
+        "@typescript-eslint/visitor-keys": "5.31.0",
+        "debug": "^4.3.4",
+        "globby": "^11.1.0",
         "is-glob": "^4.0.3",
-        "semver": "^7.3.5",
+        "semver": "^7.3.7",
         "tsutils": "^3.21.0"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "4.3.4",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+          "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "ms": "2.1.2"
+          }
+        },
+        "semver": {
+          "version": "7.3.7",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
+          "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
+          "dev": true,
+          "peer": true,
+          "requires": {
+            "lru-cache": "^6.0.0"
+          }
+        }
       }
     },
     "@typescript-eslint/utils": {
-      "version": "5.23.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.23.0.tgz",
-      "integrity": "sha512-dbgaKN21drqpkbbedGMNPCtRPZo1IOUr5EI9Jrrh99r5UW5Q0dz46RKXeSBoPV+56R6dFKpbrdhgUNSJsDDRZA==",
+      "version": "5.31.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.31.0.tgz",
+      "integrity": "sha512-kcVPdQS6VIpVTQ7QnGNKMFtdJdvnStkqS5LeALr4rcwx11G6OWb2HB17NMPnlRHvaZP38hL9iK8DdE9Fne7NYg==",
       "dev": true,
+      "peer": true,
       "requires": {
         "@types/json-schema": "^7.0.9",
-        "@typescript-eslint/scope-manager": "5.23.0",
-        "@typescript-eslint/types": "5.23.0",
-        "@typescript-eslint/typescript-estree": "5.23.0",
+        "@typescript-eslint/scope-manager": "5.31.0",
+        "@typescript-eslint/types": "5.31.0",
+        "@typescript-eslint/typescript-estree": "5.31.0",
         "eslint-scope": "^5.1.1",
         "eslint-utils": "^3.0.0"
       }
     },
     "@typescript-eslint/visitor-keys": {
-      "version": "5.23.0",
-      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.23.0.tgz",
-      "integrity": "sha512-Vd4mFNchU62sJB8pX19ZSPog05B0Y0CE2UxAZPT5k4iqhRYjPnqyY3woMxCd0++t9OTqkgjST+1ydLBi7e2Fvg==",
+      "version": "5.31.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.31.0.tgz",
+      "integrity": "sha512-ZK0jVxSjS4gnPirpVjXHz7mgdOsZUHzNYSfTw2yPa3agfbt9YfqaBiBZFSSxeBWnpWkzCxTfUpnzA3Vily/CSg==",
       "dev": true,
+      "peer": true,
       "requires": {
-        "@typescript-eslint/types": "5.23.0",
-        "eslint-visitor-keys": "^3.0.0"
+        "@typescript-eslint/types": "5.31.0",
+        "eslint-visitor-keys": "^3.3.0"
       }
     },
     "@webassemblyjs/ast": {
@@ -18632,6 +18562,7 @@
       "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
       "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
       "dev": true,
+      "peer": true,
       "requires": {}
     },
     "adjust-sourcemap-loader": {
@@ -18815,6 +18746,7 @@
       "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz",
       "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==",
       "dev": true,
+      "peer": true,
       "requires": {
         "call-bind": "^1.0.2",
         "define-properties": "^1.1.4",
@@ -18838,6 +18770,7 @@
       "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz",
       "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==",
       "dev": true,
+      "peer": true,
       "requires": {
         "call-bind": "^1.0.2",
         "define-properties": "^1.1.3",
@@ -19578,7 +19511,8 @@
       "version": "1.0.11",
       "resolved": "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz",
       "integrity": "sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "connect": {
       "version": "3.7.0",
@@ -20024,7 +19958,8 @@
       "version": "0.1.4",
       "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
       "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "default-gateway": {
       "version": "6.0.3",
@@ -20234,6 +20169,7 @@
       "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
       "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
       "dev": true,
+      "peer": true,
       "requires": {
         "esutils": "^2.0.2"
       }
@@ -20483,6 +20419,7 @@
       "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.0.tgz",
       "integrity": "sha512-URbD8tgRthKD3YcC39vbvSDrX23upXnPcnGAjQfgxXF5ID75YcENawc9ZX/9iTP9ptUyfCLIxTTuMYoRfiOVKA==",
       "dev": true,
+      "peer": true,
       "requires": {
         "call-bind": "^1.0.2",
         "es-to-primitive": "^1.2.1",
@@ -20520,6 +20457,7 @@
       "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz",
       "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==",
       "dev": true,
+      "peer": true,
       "requires": {
         "has": "^1.0.3"
       }
@@ -20529,6 +20467,7 @@
       "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
       "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
       "dev": true,
+      "peer": true,
       "requires": {
         "is-callable": "^1.1.4",
         "is-date-object": "^1.0.1",
@@ -20724,12 +20663,13 @@
       "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
     },
     "eslint": {
-      "version": "8.15.0",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.15.0.tgz",
-      "integrity": "sha512-GG5USZ1jhCu8HJkzGgeK8/+RGnHaNYZGrGDzUtigK3BsGESW/rs2az23XqE0WVwDxy1VRvvjSSGu5nB0Bu+6SA==",
+      "version": "8.20.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.20.0.tgz",
+      "integrity": "sha512-d4ixhz5SKCa1D6SCPrivP7yYVi7nyD6A4vs6HIAul9ujBzcEmZVM3/0NN/yu5nKhmO1wjp5xQ46iRfmDGlOviA==",
       "dev": true,
+      "peer": true,
       "requires": {
-        "@eslint/eslintrc": "^1.2.3",
+        "@eslint/eslintrc": "^1.3.0",
         "@humanwhocodes/config-array": "^0.9.2",
         "ajv": "^6.10.0",
         "chalk": "^4.0.0",
@@ -20747,7 +20687,7 @@
         "file-entry-cache": "^6.0.1",
         "functional-red-black-tree": "^1.0.1",
         "glob-parent": "^6.0.1",
-        "globals": "^13.6.0",
+        "globals": "^13.15.0",
         "ignore": "^5.2.0",
         "import-fresh": "^3.0.0",
         "imurmurhash": "^0.1.4",
@@ -20771,6 +20711,7 @@
           "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
           "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
           "dev": true,
+          "peer": true,
           "requires": {
             "fast-deep-equal": "^3.1.1",
             "fast-json-stable-stringify": "^2.0.0",
@@ -20783,6 +20724,7 @@
           "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
           "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
           "dev": true,
+          "peer": true,
           "requires": {
             "color-convert": "^2.0.1"
           }
@@ -20791,13 +20733,15 @@
           "version": "2.0.1",
           "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
           "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
-          "dev": true
+          "dev": true,
+          "peer": true
         },
         "chalk": {
           "version": "4.1.2",
           "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
           "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
           "dev": true,
+          "peer": true,
           "requires": {
             "ansi-styles": "^4.1.0",
             "supports-color": "^7.1.0"
@@ -20808,6 +20752,7 @@
           "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
           "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
           "dev": true,
+          "peer": true,
           "requires": {
             "color-name": "~1.1.4"
           }
@@ -20816,19 +20761,22 @@
           "version": "1.1.4",
           "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
           "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-          "dev": true
+          "dev": true,
+          "peer": true
         },
         "escape-string-regexp": {
           "version": "4.0.0",
           "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
           "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
-          "dev": true
+          "dev": true,
+          "peer": true
         },
         "eslint-scope": {
           "version": "7.1.1",
           "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
           "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
           "dev": true,
+          "peer": true,
           "requires": {
             "esrecurse": "^4.3.0",
             "estraverse": "^5.2.0"
@@ -20838,13 +20786,15 @@
           "version": "5.3.0",
           "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
           "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
-          "dev": true
+          "dev": true,
+          "peer": true
         },
         "glob-parent": {
           "version": "6.0.2",
           "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
           "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
           "dev": true,
+          "peer": true,
           "requires": {
             "is-glob": "^4.0.3"
           }
@@ -20854,6 +20804,7 @@
           "resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz",
           "integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==",
           "dev": true,
+          "peer": true,
           "requires": {
             "type-fest": "^0.20.2"
           }
@@ -20862,13 +20813,15 @@
           "version": "4.0.0",
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
           "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-          "dev": true
+          "dev": true,
+          "peer": true
         },
         "js-yaml": {
           "version": "4.1.0",
           "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
           "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
           "dev": true,
+          "peer": true,
           "requires": {
             "argparse": "^2.0.1"
           }
@@ -20877,13 +20830,15 @@
           "version": "0.4.1",
           "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
           "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
-          "dev": true
+          "dev": true,
+          "peer": true
         },
         "minimatch": {
           "version": "3.1.2",
           "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
           "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
           "dev": true,
+          "peer": true,
           "requires": {
             "brace-expansion": "^1.1.7"
           }
@@ -20893,6 +20848,7 @@
           "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
           "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
           "dev": true,
+          "peer": true,
           "requires": {
             "has-flag": "^4.0.0"
           }
@@ -20901,7 +20857,8 @@
           "version": "0.20.2",
           "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
           "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
-          "dev": true
+          "dev": true,
+          "peer": true
         }
       }
     },
@@ -20910,6 +20867,7 @@
       "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz",
       "integrity": "sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==",
       "dev": true,
+      "peer": true,
       "requires": {
         "confusing-browser-globals": "^1.0.10",
         "object.assign": "^4.1.2",
@@ -20921,7 +20879,8 @@
           "version": "6.3.0",
           "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
           "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
-          "dev": true
+          "dev": true,
+          "peer": true
         }
       }
     },
@@ -20930,6 +20889,7 @@
       "resolved": "https://registry.npmjs.org/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-17.0.0.tgz",
       "integrity": "sha512-elNiuzD0kPAPTXjFWg+lE24nMdHMtuxgYoD30OyMD6yrW1AhFZPAg27VX7d3tzOErw+dgJTNWfRSDqEcXb4V0g==",
       "dev": true,
+      "peer": true,
       "requires": {
         "eslint-config-airbnb-base": "^15.0.0"
       }
@@ -20939,6 +20899,7 @@
       "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz",
       "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==",
       "dev": true,
+      "peer": true,
       "requires": {
         "debug": "^3.2.7",
         "resolve": "^1.20.0"
@@ -20949,6 +20910,7 @@
           "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
           "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
           "dev": true,
+          "peer": true,
           "requires": {
             "ms": "^2.1.1"
           }
@@ -20960,6 +20922,7 @@
       "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz",
       "integrity": "sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ==",
       "dev": true,
+      "peer": true,
       "requires": {
         "debug": "^3.2.7",
         "find-up": "^2.1.0"
@@ -20970,6 +20933,7 @@
           "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
           "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
           "dev": true,
+          "peer": true,
           "requires": {
             "ms": "^2.1.1"
           }
@@ -20979,6 +20943,7 @@
           "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
           "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
           "dev": true,
+          "peer": true,
           "requires": {
             "locate-path": "^2.0.0"
           }
@@ -20988,6 +20953,7 @@
           "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
           "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
           "dev": true,
+          "peer": true,
           "requires": {
             "p-locate": "^2.0.0",
             "path-exists": "^3.0.0"
@@ -20998,6 +20964,7 @@
           "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
           "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
           "dev": true,
+          "peer": true,
           "requires": {
             "p-try": "^1.0.0"
           }
@@ -21007,6 +20974,7 @@
           "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
           "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
           "dev": true,
+          "peer": true,
           "requires": {
             "p-limit": "^1.1.0"
           }
@@ -21015,13 +20983,15 @@
           "version": "1.0.0",
           "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
           "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=",
-          "dev": true
+          "dev": true,
+          "peer": true
         },
         "path-exists": {
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
           "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
-          "dev": true
+          "dev": true,
+          "peer": true
         }
       }
     },
@@ -21030,6 +21000,7 @@
       "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz",
       "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==",
       "dev": true,
+      "peer": true,
       "requires": {
         "array-includes": "^3.1.4",
         "array.prototype.flat": "^1.2.5",
@@ -21051,6 +21022,7 @@
           "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
           "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
           "dev": true,
+          "peer": true,
           "requires": {
             "ms": "2.0.0"
           }
@@ -21060,6 +21032,7 @@
           "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
           "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
           "dev": true,
+          "peer": true,
           "requires": {
             "esutils": "^2.0.2"
           }
@@ -21069,6 +21042,7 @@
           "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
           "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
           "dev": true,
+          "peer": true,
           "requires": {
             "brace-expansion": "^1.1.7"
           }
@@ -21077,7 +21051,8 @@
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
           "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
-          "dev": true
+          "dev": true,
+          "peer": true
         }
       }
     },
@@ -21096,6 +21071,7 @@
       "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
       "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
       "dev": true,
+      "peer": true,
       "requires": {
         "eslint-visitor-keys": "^2.0.0"
       },
@@ -21104,7 +21080,8 @@
           "version": "2.1.0",
           "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
           "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
-          "dev": true
+          "dev": true,
+          "peer": true
         }
       }
     },
@@ -21112,7 +21089,8 @@
       "version": "3.3.0",
       "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
       "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "esotope-hammerhead": {
       "version": "0.6.1",
@@ -21127,6 +21105,7 @@
       "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz",
       "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==",
       "dev": true,
+      "peer": true,
       "requires": {
         "acorn": "^8.7.1",
         "acorn-jsx": "^5.3.2",
@@ -21144,6 +21123,7 @@
       "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
       "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
       "dev": true,
+      "peer": true,
       "requires": {
         "estraverse": "^5.1.0"
       },
@@ -21152,7 +21132,8 @@
           "version": "5.3.0",
           "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
           "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
-          "dev": true
+          "dev": true,
+          "peer": true
         }
       }
     },
@@ -21364,7 +21345,8 @@
       "version": "2.0.6",
       "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
       "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "fastq": {
       "version": "1.13.0",
@@ -21397,6 +21379,7 @@
       "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
       "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
       "dev": true,
+      "peer": true,
       "requires": {
         "flat-cache": "^3.0.4"
       }
@@ -21497,6 +21480,7 @@
       "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
       "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
       "dev": true,
+      "peer": true,
       "requires": {
         "flatted": "^3.1.0",
         "rimraf": "^3.0.2"
@@ -21584,6 +21568,7 @@
       "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz",
       "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==",
       "dev": true,
+      "peer": true,
       "requires": {
         "call-bind": "^1.0.2",
         "define-properties": "^1.1.3",
@@ -21595,7 +21580,8 @@
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
       "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "functions-have-names": {
       "version": "1.2.3",
@@ -21669,6 +21655,7 @@
       "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz",
       "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==",
       "dev": true,
+      "peer": true,
       "requires": {
         "call-bind": "^1.0.2",
         "get-intrinsic": "^1.1.1"
@@ -21750,7 +21737,8 @@
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
       "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "has-flag": {
       "version": "3.0.0",
@@ -22167,6 +22155,7 @@
       "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz",
       "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==",
       "dev": true,
+      "peer": true,
       "requires": {
         "get-intrinsic": "^1.1.0",
         "has": "^1.0.3",
@@ -22223,6 +22212,7 @@
       "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
       "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
       "dev": true,
+      "peer": true,
       "requires": {
         "has-bigints": "^1.0.1"
       }
@@ -22241,6 +22231,7 @@
       "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
       "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
       "dev": true,
+      "peer": true,
       "requires": {
         "call-bind": "^1.0.2",
         "has-tostringtag": "^1.0.0"
@@ -22250,7 +22241,8 @@
       "version": "1.2.4",
       "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz",
       "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "is-ci": {
       "version": "1.2.1",
@@ -22332,7 +22324,8 @@
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz",
       "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "is-number": {
       "version": "7.0.0",
@@ -22344,6 +22337,7 @@
       "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
       "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
       "dev": true,
+      "peer": true,
       "requires": {
         "has-tostringtag": "^1.0.0"
       }
@@ -22399,6 +22393,7 @@
       "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz",
       "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==",
       "dev": true,
+      "peer": true,
       "requires": {
         "call-bind": "^1.0.2"
       }
@@ -22413,6 +22408,7 @@
       "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
       "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
       "dev": true,
+      "peer": true,
       "requires": {
         "has-tostringtag": "^1.0.0"
       }
@@ -22422,6 +22418,7 @@
       "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
       "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
       "dev": true,
+      "peer": true,
       "requires": {
         "has-symbols": "^1.0.2"
       }
@@ -22442,6 +22439,7 @@
       "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
       "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==",
       "dev": true,
+      "peer": true,
       "requires": {
         "call-bind": "^1.0.2"
       }
@@ -22652,7 +22650,8 @@
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
       "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "json5": {
       "version": "2.2.1",
@@ -22975,6 +22974,7 @@
       "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
       "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
       "dev": true,
+      "peer": true,
       "requires": {
         "prelude-ls": "^1.2.1",
         "type-check": "~0.4.0"
@@ -23068,7 +23068,8 @@
       "version": "4.6.2",
       "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
       "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "lodash.once": {
       "version": "4.1.1",
@@ -23509,7 +23510,8 @@
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
       "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "needle": {
       "version": "2.9.1",
@@ -23554,11 +23556,11 @@
       "requires": {}
     },
     "ngx-tiptap": {
-      "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/ngx-tiptap/-/ngx-tiptap-3.0.4.tgz",
-      "integrity": "sha512-iU69pGqYoan5v9N8l92tpFSncB7x5mbXcJVwJwUDtEI922N+59cd4pw5y+NrN3er9E/HVAgOLfRB40TDHliwqQ==",
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/ngx-tiptap/-/ngx-tiptap-5.0.0.tgz",
+      "integrity": "sha512-SlySnakZ7OroJSG5owPqVQ1ncqS9tgWYQ7551aI2VzZmcdCKKss00cdy+TqNyeRUg0b1+9Ep+yorUmg2CHPKLg==",
       "requires": {
-        "tslib": "^2.2.0"
+        "tslib": "^2.3.0"
       }
     },
     "ngx-translate-testing": {
@@ -23951,6 +23953,7 @@
       "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz",
       "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==",
       "dev": true,
+      "peer": true,
       "requires": {
         "call-bind": "^1.0.2",
         "define-properties": "^1.1.3",
@@ -23962,6 +23965,7 @@
       "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz",
       "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==",
       "dev": true,
+      "peer": true,
       "requires": {
         "call-bind": "^1.0.2",
         "define-properties": "^1.1.3",
@@ -24021,6 +24025,7 @@
       "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
       "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
       "dev": true,
+      "peer": true,
       "requires": {
         "deep-is": "^0.1.3",
         "fast-levenshtein": "^2.0.6",
@@ -24099,9 +24104,9 @@
       }
     },
     "orderedmap": {
-      "version": "1.1.7",
-      "resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-1.1.7.tgz",
-      "integrity": "sha512-B1SuadDDwIRXXutaJQ1xjreGL3hxujpexBG4PquoXbgJD8bjp2k8b8qI/mk7q0LUdIx7T8IALWB8mPbfsjbGCw=="
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/orderedmap/-/orderedmap-2.0.0.tgz",
+      "integrity": "sha512-buf4PoAMlh45b8a8gsGy/X6w279TSqkyAS0C0wdTSJwFSU+ljQFJON5I8NfjLHoCXwpSROIo2wr0g33T+kQshQ=="
     },
     "os-family": {
       "version": "1.1.0",
@@ -24816,7 +24821,8 @@
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
       "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "pretty-bytes": {
       "version": "5.6.0",
@@ -24859,93 +24865,63 @@
       }
     },
     "prosemirror-commands": {
-      "version": "1.2.2",
-      "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.2.2.tgz",
-      "integrity": "sha512-TX+KpWudMon06frryfpO/u7hsQv2hu8L4VSVbCpi3/7wXHBgl+35mV85qfa3RpT8xD2f3MdeoTqH0vy5JdbXPg==",
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/prosemirror-commands/-/prosemirror-commands-1.3.0.tgz",
+      "integrity": "sha512-BwBbZ5OAScPcm0x7H8SPbqjuEJnCU2RJT9LDyOiiIl/3NbL1nJZI4SFNHwU2e/tRr2Xe7JsptpzseqvZvToLBQ==",
       "requires": {
         "prosemirror-model": "^1.0.0",
         "prosemirror-state": "^1.0.0",
         "prosemirror-transform": "^1.0.0"
       }
     },
-    "prosemirror-dropcursor": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/prosemirror-dropcursor/-/prosemirror-dropcursor-1.4.0.tgz",
-      "integrity": "sha512-6+YwTjmqDwlA/Dm+5wK67ezgqgjA/MhSDgaNxKUzH97SmeuWFXyLeDRxxOPZeSo7yTxcDGUCWTEjmQZsVBuMrQ==",
-      "requires": {
-        "prosemirror-state": "^1.0.0",
-        "prosemirror-transform": "^1.1.0",
-        "prosemirror-view": "^1.1.0"
-      }
-    },
-    "prosemirror-gapcursor": {
-      "version": "1.2.2",
-      "resolved": "https://registry.npmjs.org/prosemirror-gapcursor/-/prosemirror-gapcursor-1.2.2.tgz",
-      "integrity": "sha512-7YzuRBbu9W7HGQde84kCHfIjaRLNcAdeijbgqrm/R9dsdTWkV+rrdcmic/sCc+bptiNpvjCEE+R6hrbT8zFQeQ==",
-      "requires": {
-        "prosemirror-keymap": "^1.0.0",
-        "prosemirror-model": "^1.0.0",
-        "prosemirror-state": "^1.0.0",
-        "prosemirror-view": "^1.0.0"
-      }
-    },
-    "prosemirror-history": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/prosemirror-history/-/prosemirror-history-1.2.0.tgz",
-      "integrity": "sha512-B9v9xtf4fYbKxQwIr+3wtTDNLDZcmMMmGiI3TAPShnUzvo+Rmv1GiUrsQChY1meetHl7rhML2cppF3FTs7f7UQ==",
-      "requires": {
-        "prosemirror-state": "^1.2.2",
-        "prosemirror-transform": "^1.0.0",
-        "rope-sequence": "^1.3.0"
-      }
-    },
     "prosemirror-keymap": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.1.5.tgz",
-      "integrity": "sha512-8SZgPH3K+GLsHL2wKuwBD9rxhsbnVBTwpHCO4VUO5GmqUQlxd/2GtBVWTsyLq4Dp3N9nGgPd3+lZFKUDuVp+Vw==",
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/prosemirror-keymap/-/prosemirror-keymap-1.2.0.tgz",
+      "integrity": "sha512-TdSfu+YyLDd54ufN/ZeD1VtBRYpgZnTPnnbY+4R08DDgs84KrIPEPbJL8t1Lm2dkljFx6xeBE26YWH3aIzkPKg==",
       "requires": {
         "prosemirror-state": "^1.0.0",
         "w3c-keyname": "^2.2.0"
       }
     },
     "prosemirror-model": {
-      "version": "1.16.1",
-      "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.16.1.tgz",
-      "integrity": "sha512-r1/w0HDU40TtkXp0DyKBnFPYwd8FSlUSJmGCGFv4DeynfeSlyQF2FD0RQbVEMOe6P3PpUSXM6LZBV7W/YNZ4mA==",
+      "version": "1.18.1",
+      "resolved": "https://registry.npmjs.org/prosemirror-model/-/prosemirror-model-1.18.1.tgz",
+      "integrity": "sha512-IxSVBKAEMjD7s3n8cgtwMlxAXZrC7Mlag7zYsAKDndAqnDScvSmp/UdnRTV/B33lTCVU3CCm7dyAn/rVVD0mcw==",
       "requires": {
-        "orderedmap": "^1.1.0"
+        "orderedmap": "^2.0.0"
       }
     },
     "prosemirror-schema-list": {
-      "version": "1.1.6",
-      "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.1.6.tgz",
-      "integrity": "sha512-aFGEdaCWmJzouZ8DwedmvSsL50JpRkqhQ6tcpThwJONVVmCgI36LJHtoQ4VGZbusMavaBhXXr33zyD2IVsTlkw==",
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/prosemirror-schema-list/-/prosemirror-schema-list-1.2.0.tgz",
+      "integrity": "sha512-8PT/9xOx1HHdC7fDNNfhQ50Z8Mzu7nKyA1KCDltSpcZVZIbB0k7KtsHrnXyuIhbLlScoymBiLZ00c5MH6wdFsA==",
       "requires": {
         "prosemirror-model": "^1.0.0",
+        "prosemirror-state": "^1.0.0",
         "prosemirror-transform": "^1.0.0"
       }
     },
     "prosemirror-state": {
-      "version": "1.3.4",
-      "resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.3.4.tgz",
-      "integrity": "sha512-Xkkrpd1y/TQ6HKzN3agsQIGRcLckUMA9u3j207L04mt8ToRgpGeyhbVv0HI7omDORIBHjR29b7AwlATFFf2GLA==",
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/prosemirror-state/-/prosemirror-state-1.4.1.tgz",
+      "integrity": "sha512-U/LBDW2gNmVa07sz/D229XigSdDQ5CLFwVB1Vb32MJbAHHhWe/6pOc721faI17tqw4pZ49i1xfY/jEZ9tbIhPg==",
       "requires": {
         "prosemirror-model": "^1.0.0",
         "prosemirror-transform": "^1.0.0"
       }
     },
     "prosemirror-transform": {
-      "version": "1.4.2",
-      "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.4.2.tgz",
-      "integrity": "sha512-bcIsf3uRZhfab0xRfyyxOEh6eqSszq/hJbDbmUumFnbHBoWhB/uXbpz6vvUxfk0XiEvrZDJ+5pXRrNDc1Hu3vQ==",
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/prosemirror-transform/-/prosemirror-transform-1.6.0.tgz",
+      "integrity": "sha512-MAp7AjsjEGEqQY0sSMufNIUuEyB1ZR9Fqlm8dTwwWwpEJRv/plsKjWXBbx52q3Ml8MtaMcd7ic14zAHVB3WaMw==",
       "requires": {
         "prosemirror-model": "^1.0.0"
       }
     },
     "prosemirror-view": {
-      "version": "1.23.13",
-      "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.23.13.tgz",
-      "integrity": "sha512-X/NcwZv8pgcEWfs3n++Wz4nDgqDIeDvJ9kfCk6DCoC9XUlDekqJLFt9wCcCUBXedb8hs/dmd+JmcaLgbr67XZw==",
+      "version": "1.26.2",
+      "resolved": "https://registry.npmjs.org/prosemirror-view/-/prosemirror-view-1.26.2.tgz",
+      "integrity": "sha512-CGKw+GadkfSBEwRAJTHCEKJ4DlV6/3IhAdjpwGyZHUHtbP7jX4Ol4zmi7xa2c6GOabDlIJLYXJydoNYLX7lNeQ==",
       "requires": {
         "prosemirror-model": "^1.16.0",
         "prosemirror-state": "^1.0.0",
@@ -25148,7 +25124,8 @@
       "version": "3.2.0",
       "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
       "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "regexpu-core": {
       "version": "5.0.1",
@@ -25322,11 +25299,6 @@
         "glob": "^7.1.3"
       }
     },
-    "rope-sequence": {
-      "version": "1.3.3",
-      "resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.3.tgz",
-      "integrity": "sha512-85aZYCxweiD5J8yTEbw+E6A27zSnLPNDL0WfPdw3YYodq7WjnTKo0q4dtyQ2gz23iPT8Q9CUyJtAaUNcTxRf5Q=="
-    },
     "run-async": {
       "version": "2.4.1",
       "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
@@ -25900,6 +25872,7 @@
       "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz",
       "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==",
       "dev": true,
+      "peer": true,
       "requires": {
         "call-bind": "^1.0.2",
         "define-properties": "^1.1.4",
@@ -25911,6 +25884,7 @@
       "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz",
       "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==",
       "dev": true,
+      "peer": true,
       "requires": {
         "call-bind": "^1.0.2",
         "define-properties": "^1.1.4",
@@ -25943,7 +25917,8 @@
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
       "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "stylus": {
       "version": "0.56.0",
@@ -26695,6 +26670,7 @@
       "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz",
       "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==",
       "dev": true,
+      "peer": true,
       "requires": {
         "@types/json5": "^0.0.29",
         "json5": "^1.0.1",
@@ -26707,6 +26683,7 @@
           "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
           "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
           "dev": true,
+          "peer": true,
           "requires": {
             "minimist": "^1.2.0"
           }
@@ -26715,7 +26692,8 @@
           "version": "3.0.0",
           "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
           "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
-          "dev": true
+          "dev": true,
+          "peer": true
         }
       }
     },
@@ -26729,6 +26707,7 @@
       "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
       "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
       "dev": true,
+      "peer": true,
       "requires": {
         "tslib": "^1.8.1"
       },
@@ -26737,7 +26716,8 @@
           "version": "1.14.1",
           "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
           "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
-          "dev": true
+          "dev": true,
+          "peer": true
         }
       }
     },
@@ -26754,6 +26734,7 @@
       "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
       "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
       "dev": true,
+      "peer": true,
       "requires": {
         "prelude-ls": "^1.2.1"
       }
@@ -26802,6 +26783,7 @@
       "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
       "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==",
       "dev": true,
+      "peer": true,
       "requires": {
         "call-bind": "^1.0.2",
         "has-bigints": "^1.0.2",
@@ -26907,7 +26889,8 @@
       "version": "2.3.0",
       "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
       "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "validate-npm-package-name": {
       "version": "3.0.0",
@@ -26931,9 +26914,9 @@
       "dev": true
     },
     "w3c-keyname": {
-      "version": "2.2.4",
-      "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.4.tgz",
-      "integrity": "sha512-tOhfEwEzFLJzf6d1ZPkYfGj+FWhIpBux9ppoP3rlclw3Z0BZv3N7b7030Z1kYth+6rDuAsXUFr+d0VE6Ed1ikw=="
+      "version": "2.2.5",
+      "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.5.tgz",
+      "integrity": "sha512-WJrK7i6w+ULuZsGscCezbCH4Aev5U3xY87vnSimzzEgPQhb0Sa0a1rE3c2jtEwrFtSfi61Jefw3jI5/DD/3jbQ=="
     },
     "watchpack": {
       "version": "2.3.1",
@@ -27239,6 +27222,7 @@
       "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
       "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
       "dev": true,
+      "peer": true,
       "requires": {
         "is-bigint": "^1.0.1",
         "is-boolean-object": "^1.1.0",
@@ -27299,7 +27283,8 @@
       "version": "1.2.3",
       "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
       "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
-      "dev": true
+      "dev": true,
+      "peer": true
     },
     "wrap-ansi": {
       "version": "2.1.0",
diff --git a/package.json b/package.json
index 70a51689f1d5b82a122144801c1983bad85e9169..96962030e556a468dd383938d442e638693616cd 100644
--- a/package.json
+++ b/package.json
@@ -13,6 +13,8 @@
     "start-player-local-network": "ng serve player --port 4202 --host 0.0.0.0",
     "build-editor": "ng build --project editor --output-hashing=none && scripts/build.sh editor $npm_package_config_editor_version",
     "build-player": "ng build --project player --output-hashing=none && scripts/build.sh player $npm_package_config_player_version",
+    "node-build-editor": "ng build --project editor --output-hashing=none && node scripts/wrap_and_pack.js editor $npm_package_config_editor_version projects/editor/src/html_wrapper/index.html",
+    "node-build-player": "ng build --project player --output-hashing=none && node scripts/wrap_and_pack.js player $npm_package_config_player_version projects/player/src/html_wrapper/index.html",
     "test": "ng test",
     "e2e": "node node_modules/testcafe/bin/testcafe.js 'chrome' e2e-tests/editor/test.ts"
   },
@@ -22,6 +24,9 @@
     "parserOptions": {
       "project": "./tsconfig.json"
     },
+    "rules": {
+      "class-methods-use-this": ["error", { "exceptMethods": ["getElementComponent", "getNewOptionLabel", "transform"] }]
+    },
     "overrides": [
       {
         "files": [
@@ -56,28 +61,31 @@
     "@angular/router": "~13.3.0",
     "@ngx-translate/core": "^14.0.0",
     "@ngx-translate/http-loader": "^6.0.0",
-    "@tiptap/core": "^2.0.0-beta.175",
-    "@tiptap/extension-blockquote": "^2.0.0-beta.26",
-    "@tiptap/extension-bubble-menu": "^2.0.0-beta.56",
-    "@tiptap/extension-bullet-list": "^2.0.0-beta.26",
-    "@tiptap/extension-color": "^2.0.0-beta.9",
-    "@tiptap/extension-floating-menu": "^2.0.0-beta.51",
-    "@tiptap/extension-font-family": "^2.0.0-beta.21",
-    "@tiptap/extension-heading": "^2.0.0-beta.26",
-    "@tiptap/extension-highlight": "^2.0.0-beta.33",
-    "@tiptap/extension-image": "^2.0.0-beta.27",
-    "@tiptap/extension-list-item": "^2.0.0-beta.20",
-    "@tiptap/extension-ordered-list": "^2.0.0-beta.27",
-    "@tiptap/extension-paragraph": "^2.0.0-beta.23",
-    "@tiptap/extension-strike": "~2.0.0-beta.27",
-    "@tiptap/extension-subscript": "^2.0.0-beta.10",
-    "@tiptap/extension-superscript": "^2.0.0-beta.10",
-    "@tiptap/extension-text-align": "^2.0.0-beta.29",
-    "@tiptap/extension-text-style": "^2.0.0-beta.23",
-    "@tiptap/extension-underline": "^2.0.0-beta.23",
-    "@tiptap/starter-kit": "2.0.0-beta.184",
-    "ngx-tiptap": "^3.0.4",
-    "prosemirror-state": "^1.3.4",
+    "@tiptap/core": "^2.0.0-beta.182",
+    "@tiptap/extension-blockquote": "^2.0.0-beta.29",
+    "@tiptap/extension-bold": "^2.0.0-beta.28",
+    "@tiptap/extension-bubble-menu": "^2.0.0-beta.61",
+    "@tiptap/extension-bullet-list": "^2.0.0-beta.29",
+    "@tiptap/extension-color": "^2.0.0-beta.12",
+    "@tiptap/extension-document": "^2.0.0-beta.17",
+    "@tiptap/extension-floating-menu": "^2.0.0-beta.56",
+    "@tiptap/extension-font-family": "^2.0.0-beta.24",
+    "@tiptap/extension-heading": "^2.0.0-beta.29",
+    "@tiptap/extension-highlight": "^2.0.0-beta.35",
+    "@tiptap/extension-image": "^2.0.0-beta.30",
+    "@tiptap/extension-italic": "^2.0.0-beta.28",
+    "@tiptap/extension-list-item": "^2.0.0-beta.23",
+    "@tiptap/extension-ordered-list": "^2.0.0-beta.30",
+    "@tiptap/extension-paragraph": "^2.0.0-beta.26",
+    "@tiptap/extension-strike": "~2.0.0-beta.29",
+    "@tiptap/extension-subscript": "^2.0.0-beta.13",
+    "@tiptap/extension-superscript": "^2.0.0-beta.13",
+    "@tiptap/extension-text": "^2.0.0-beta.17",
+    "@tiptap/extension-text-align": "^2.0.0-beta.31",
+    "@tiptap/extension-text-style": "^2.0.0-beta.26",
+    "@tiptap/extension-underline": "^2.0.0-beta.25",
+    "ngx-tiptap": "^5.0.0",
+    "prosemirror-state": "^1.4.1",
     "rxjs": "^7.4.0",
     "testcafe": "^1.18.6",
     "tslib": "^2.1.0",
@@ -87,7 +95,7 @@
     "@angular-devkit/build-angular": "~13.3.0",
     "@angular/cli": "~13.3.0",
     "@angular/compiler-cli": "~13.3.0",
-    "@iqb/eslint-config": "^1.1.1",
+    "@iqb/eslint-config": "^2.1.1",
     "@types/jasmine": "~3.6.0",
     "@types/node": "^12.11.7",
     "iqb-dev-components": "^1.4.0",
diff --git a/projects/common/assets/common-styles.css b/projects/common/assets/common-styles.css
index f700034a0e7c6448fcc8b498249456b9acb0f5d0..9aac3c04ba2a00f1e5ee8dc2d82f3a4c41b63e04 100644
--- a/projects/common/assets/common-styles.css
+++ b/projects/common/assets/common-styles.css
@@ -54,3 +54,14 @@ blockquote p {
 .fixed-size-content {
   overflow: auto;
 }
+
+.snackbar-warning {border: 3px double #ff4d4d}
+.snackbar-error {background-color: #ff4d4d}
+.snackbar-success {background-color: green}
+
+.cdk-drag {
+  cursor: grab;
+}
+.cdk-drag-dragging {
+  cursor: grabbing;
+}
diff --git a/projects/common/components/button/button.component.ts b/projects/common/components/button/button.component.ts
index 9e46f7717bacd3a1ef7a7b3d65218bbc8489002d..efb0e597e8cde230dd8a841d56a7ffed530f5d9d 100644
--- a/projects/common/components/button/button.component.ts
+++ b/projects/common/components/button/button.component.ts
@@ -24,6 +24,7 @@ import { ButtonElement } from 'common/models/elements/button/button';
                                               action: elementModel.action,
                                               param: elementModel.actionParam
                                            }) : false">
+<!--TODO why prevent default?-->
       {{elementModel.label}}
     </a>
     <button *ngIf="!elementModel.imageSrc && !elementModel.asLink" mat-button
diff --git a/projects/common/components/compound-elements/cloze/cloze-child-elements/drop-list-simple.component.ts b/projects/common/components/compound-elements/cloze/cloze-child-elements/drop-list-simple.component.ts
index 71773d295bea7dedbf66142e2dbd9dae51733589..12351f167305ef302a9fdf8cf0d9c29eb034fc4f 100644
--- a/projects/common/components/compound-elements/cloze/cloze-child-elements/drop-list-simple.component.ts
+++ b/projects/common/components/compound-elements/cloze/cloze-child-elements/drop-list-simple.component.ts
@@ -73,6 +73,7 @@ import { DragNDropValueObject } from 'common/models/elements/element';
     '.list {width: 100%; height: 100%; border-radius: 5px}',
     '.item {border-radius: 5px; padding: 0 5px; height: 100%; text-align: center;}',
     '.item:not(:last-child) {margin-bottom: 5px;}',
+    '.item:active {cursor: grabbing}',
     '.error-message {font-size: 75%; margin-top: 10px;}',
     '.cdk-drag-preview {padding: 8px 20px; border-radius: 10px}',
     '.drag-placeholder {background-color: lightgrey; border: dotted 3px #999;}',
diff --git a/projects/common/components/compound-elements/cloze/cloze-child-elements/text-field-simple.component.ts b/projects/common/components/compound-elements/cloze/cloze-child-elements/text-field-simple.component.ts
index 8783a49eb176425915eab58489440c4970b643b5..935c337b34a39386b03ed9c1c5041ea460ad38e4 100644
--- a/projects/common/components/compound-elements/cloze/cloze-child-elements/text-field-simple.component.ts
+++ b/projects/common/components/compound-elements/cloze/cloze-child-elements/text-field-simple.component.ts
@@ -32,7 +32,9 @@ import {
   `,
   styles: [
     '.clozeChild {border: 1px solid rgba(0,0,0,.12); border-radius: 5px}',
-    'input {width: calc(100% - 2px); height: calc(100% - 2px); vertical-align: top; padding: 0;}'
+    'input {width: calc(100% - 2px); height: calc(100% - 2px); vertical-align: top; padding: 0;}',
+    'input:hover {border: 1px solid currentColor;}',
+    'input:focus {outline: 1px solid #3f51b5;}'
   ]
 })
 export class TextFieldSimpleComponent extends FormElementComponent {
diff --git a/projects/common/components/compound-elements/cloze/cloze-child-elements/toggle-button.component.ts b/projects/common/components/compound-elements/cloze/cloze-child-elements/toggle-button.component.ts
index e5e64bcd1452e415b612567e44a49d376ce282f0..e77498d3cf68ef2ea4139b5fabb5f22c57a01deb 100644
--- a/projects/common/components/compound-elements/cloze/cloze-child-elements/toggle-button.component.ts
+++ b/projects/common/components/compound-elements/cloze/cloze-child-elements/toggle-button.component.ts
@@ -1,19 +1,19 @@
 import { Component, Input } from '@angular/core';
-import { FormElementComponent } from '../../../../directives/form-element-component.directive';
+import { FormElementComponent } from 'common/directives/form-element-component.directive';
 import { ToggleButtonElement } from 'common/models/elements/compound-elements/cloze/cloze-child-elements/toggle-button';
 
 @Component({
   selector: 'aspect-toggle-button',
   template: `
     <mat-button-toggle-group [formControl]="elementFormControl"
+                             [disabled]="elementModel.readOnly"
                              [value]="elementModel.value"
                              [vertical]="elementModel.verticalOrientation"
                              [style.width]="elementModel.dynamicWidth ? 'unset' : '100%'">
       <mat-button-toggle *ngFor="let option of elementModel.richTextOptions; let i = index"
                          [value]="i"
-                         [ngClass]="{ 'strike' : elementModel.strikeOtherOptions &&
-                                                 elementFormControl.value !== null &&
-                                                 elementFormControl.value !== i }"
+                         [ngClass]="{ 'strike-other-options' : elementModel.strikeOtherOptions,
+                                      'strike-selected-option' : elementModel.strikeSelectedOption }"
                          [style.color]="elementModel.styling.fontColor"
                          [style.font-size.px]="elementModel.styling.fontSize"
                          [style.font-weight]="elementModel.styling.bold ? 'bold' : ''"
@@ -33,7 +33,10 @@ import { ToggleButtonElement } from 'common/models/elements/compound-elements/cl
     'mat-button-toggle-group {display: inline-flex; min-width: 70px; min-height: 20px; max-width: 100%;}',
     'mat-button-toggle-group {justify-content: center;}',
     ':host ::ng-deep .mat-button-toggle-label-content {line-height: unset}',
-    ':host ::ng-deep .strike .mat-button-toggle-label-content {text-decoration: line-through}',
+    ':host ::ng-deep .strike-selected-option.mat-button-toggle-checked .mat-button-toggle-label-content' +
+    '{text-decoration: line-through}',
+    ':host ::ng-deep .strike-other-options:not(.mat-button-toggle-checked) .mat-button-toggle-label-content' +
+    '{text-decoration: line-through}'
   ]
 })
 export class ToggleButtonComponent extends FormElementComponent {
diff --git a/projects/common/components/compound-elements/cloze/cloze.component.ts b/projects/common/components/compound-elements/cloze/cloze.component.ts
index c556fb5d9d951d7ea23a277c810cee9c49a79cfa..9d7ebbde1917de31d61c48fc007737d2ef3ef277 100644
--- a/projects/common/components/compound-elements/cloze/cloze.component.ts
+++ b/projects/common/components/compound-elements/cloze/cloze.component.ts
@@ -11,9 +11,6 @@ import { ClozeElement } from 'common/models/elements/compound-elements/cloze/clo
 @Component({
   selector: 'aspect-cloze',
   template: `
-    <ng-container *ngIf="elementModel.document.content.length < 1">
-      <i>Kein Dokument vorhanden</i>
-    </ng-container>
     <div [style.width.%]="100"
          [style.height]="'auto'"
          [style.column-count]="elementModel.columnCount">
diff --git a/projects/common/components/compound-elements/likert/likert-radio-button-group.component.ts b/projects/common/components/compound-elements/likert/likert-radio-button-group.component.ts
index d010e3ef0b3c09fe48d24934f2ba8ae1fb0fb1f6..e802b20e639526d26a8395a8dff89ef553c8c43d 100644
--- a/projects/common/components/compound-elements/likert/likert-radio-button-group.component.ts
+++ b/projects/common/components/compound-elements/likert/likert-radio-button-group.component.ts
@@ -1,5 +1,5 @@
 import { Component, Input } from '@angular/core';
-import { FormElementComponent } from '../../../directives/form-element-component.directive';
+import { FormElementComponent } from 'common/directives/form-element-component.directive';
 import { LikertRowElement } from 'common/models/elements/compound-elements/likert/likert-row';
 
 @Component({
@@ -17,15 +17,15 @@ import { LikertRowElement } from 'common/models/elements/compound-elements/liker
            [style.grid-row-end]="2"
            [style.place-self]="'start'"
            [style.align-items]="'center'"
-           [fxLayout]="elementModel.rowLabel.position === 'left' ||
-                     elementModel.rowLabel.position === 'right' ? 'row' : 'column'">
+           [fxLayout]="elementModel.rowLabel.imgPosition === 'left' ||
+                     elementModel.rowLabel.imgPosition === 'right' ? 'row' : 'column'">
         <img *ngIf="elementModel.rowLabel.imgSrc &&
-                    (elementModel.rowLabel.position === 'above' || elementModel.rowLabel.position === 'left')"
+                    (elementModel.rowLabel.imgPosition === 'above' || elementModel.rowLabel.imgPosition === 'left')"
              [src]="elementModel.rowLabel.imgSrc | safeResourceUrl" alt="Image Placeholder"
              [style.object-fit]="'scale-down'" [style.max-width.%]="100">
-        <ng-container>{{elementModel.rowLabel.text}}</ng-container>
+        <div [innerHTML]="elementModel.rowLabel.text"></div>
         <img *ngIf="elementModel.rowLabel.imgSrc &&
-                    (elementModel.rowLabel.position === 'below' || elementModel.rowLabel.position === 'right')"
+                    (elementModel.rowLabel.imgPosition === 'below' || elementModel.rowLabel.imgPosition === 'right')"
              [src]="elementModel.rowLabel.imgSrc | safeResourceUrl" alt="Image Placeholder"
              [style.object-fit]="'scale-down'" [style.max-width.%]="100">
       </div>
diff --git a/projects/common/components/compound-elements/likert/likert.component.ts b/projects/common/components/compound-elements/likert/likert.component.ts
index baeac85d2e8ca395630fc4e33683f3751c117b11..b82960fdc485e1e308a6e741619c2cac4651e4f3 100644
--- a/projects/common/components/compound-elements/likert/likert.component.ts
+++ b/projects/common/components/compound-elements/likert/likert.component.ts
@@ -1,24 +1,33 @@
 import {
   Component, Input, QueryList, ViewChildren
 } from '@angular/core';
-import { LikertRadioButtonGroupComponent } from './likert-radio-button-group.component';
-import { CompoundElementComponent } from '../../../directives/compound-element.directive';
-import { ElementComponent } from '../../../directives/element-component.directive';
+import { CompoundElementComponent } from 'common/directives/compound-element.directive';
+import { ElementComponent } from 'common/directives/element-component.directive';
 import { LikertElement } from 'common/models/elements/compound-elements/likert/likert';
-import { LikertRowElement } from 'common/models/elements/compound-elements/likert/likert-row';
+import { LikertRadioButtonGroupComponent } from './likert-radio-button-group.component';
 
 @Component({
   selector: 'aspect-likert',
   template: `
-    <div *ngIf="elementModel.rows.length === 0 && elementModel.columns.length === 0">
+    <div *ngIf="elementModel.rows.length === 0 && elementModel.options.length === 0">
       Keine Zeilen oder Spalten vorhanden
     </div>
     <div [style.width.%]="100"
          [style.height.%]="100">
+      <div class="label"
+           [style.color]="elementModel.styling.fontColor"
+           [style.font-family]="elementModel.styling.font"
+           [style.font-size.px]="elementModel.styling.fontSize"
+           [style.line-height.%]="elementModel.styling.lineHeight"
+           [style.font-weight]="elementModel.styling.bold ? 'bold' : ''"
+           [style.font-style]="elementModel.styling.italic ? 'italic' : ''"
+           [style.text-decoration]="elementModel.styling.underline ? 'underline' : ''">
+        {{elementModel.label}}
+      </div>
       <div class="mat-typography"
            [style.display]="'grid'"
            [style.grid-template-columns]="elementModel.firstColumnSizeRatio + 'fr ' +
-                                    '1fr '.repeat(elementModel.columns.length)"
+                                          '1fr '.repeat(elementModel.options.length)"
            [style.background-color]="elementModel.styling.backgroundColor"
            [style.color]="elementModel.styling.fontColor"
            [style.font-family]="elementModel.styling.font"
@@ -27,17 +36,24 @@ import { LikertRowElement } from 'common/models/elements/compound-elements/liker
            [style.font-weight]="elementModel.styling.bold ? 'bold' : ''"
            [style.font-style]="elementModel.styling.italic ? 'italic' : ''"
            [style.text-decoration]="elementModel.styling.underline ? 'underline' : ''">
-        <div *ngFor="let column of elementModel.columns; let i = index"
+        <div *ngIf="elementModel.options.length > 0"
+             [style.grid-column-start]="1"
+             [style.grid-column-end]="1"
+             [style.grid-row-start]="1"
+             [style.grid-row-end]="1">
+          {{elementModel.label2}}
+        </div>
+        <div *ngFor="let column of elementModel.options; let i = index"
              class="columns" fxLayout="column" fxLayoutAlign="end center"
              [style.grid-column-start]="2 + i"
              [style.grid-column-end]="3 + i"
              [style.grid-row-start]="1"
              [style.grid-row-end]="2">
-          <img *ngIf="column.imgSrc && column.position === 'above'"
+          <img *ngIf="column.imgSrc && column.imgPosition === 'above'"
                [src]="column.imgSrc | safeResourceUrl" alt="Image Placeholder"
                [style.object-fit]="'scale-down'">
           <div [innerHTML]="sanitizer.bypassSecurityTrustHtml(column.text)"></div>
-          <img *ngIf="column.imgSrc && column.position === 'below'"
+          <img *ngIf="column.imgSrc && column.imgPosition === 'below'"
                [src]="column.imgSrc | safeResourceUrl" alt="Image Placeholder"
                [style.object-fit]="'scale-down'">
         </div>
@@ -47,7 +63,7 @@ import { LikertRowElement } from 'common/models/elements/compound-elements/liker
             [style.background-color]="elementModel.styling.lineColoring && i % 2 === 0 ?
                                       elementModel.styling.lineColoringColor : ''"
             [style.grid-column-start]="1"
-            [style.grid-column-end]="elementModel.columns.length + 2"
+            [style.grid-column-end]="elementModel.options.length + 2"
             [style.grid-row-start]="2 + i"
             [style.grid-row-end]="3 + i"
             [style.padding.px]="3"
@@ -62,7 +78,8 @@ import { LikertRowElement } from 'common/models/elements/compound-elements/liker
   styles: [
     'img {object-fit: contain; max-height: 100%; max-width: 100%; margin: 10px}',
     '.columns {text-align: center;}',
-    ':host ::ng-deep mat-radio-button span.mat-radio-container {left: calc(50% - 10px)}'
+    ':host ::ng-deep mat-radio-button span.mat-radio-container {left: calc(50% - 10px)}',
+    '.label {margin-bottom: 10px;}'
   ]
 })
 export class LikertComponent extends CompoundElementComponent {
diff --git a/projects/common/components/frame/frame.component.ts b/projects/common/components/frame/frame.component.ts
index c731c1352cd920551f74672e49a1bc4bdfd7f663..a8317ef778161f03e59103800de2a0637636e541 100644
--- a/projects/common/components/frame/frame.component.ts
+++ b/projects/common/components/frame/frame.component.ts
@@ -1,17 +1,20 @@
 import { Component, Input } from '@angular/core';
-import { ElementComponent } from '../../directives/element-component.directive';
 import { FrameElement } from 'common/models/elements/frame/frame';
+import { ElementComponent } from '../../directives/element-component.directive';
 
 @Component({
   selector: 'aspect-frame',
   template: `
     <div [style.width]="'calc(100% - ' + (elementModel.styling.borderWidth * 2) + 'px)'"
          [style.height]="'calc(100% - ' + (elementModel.styling.borderWidth * 2) + 'px)'"
-         [style.border-style]="elementModel.styling.borderStyle"
          [style.border-width.px]="elementModel.styling.borderWidth"
          [style.border-color]="elementModel.styling.borderColor"
          [style.border-radius.px]="elementModel.styling.borderRadius"
-         [style.background-color]="elementModel.styling.backgroundColor">
+         [style.background-color]="elementModel.styling.backgroundColor"
+         [style.border-top-style]="elementModel.hasBorderTop ? elementModel.styling.borderStyle : 'none'"
+         [style.border-bottom-style]="elementModel.hasBorderBottom ? elementModel.styling.borderStyle : 'none'"
+         [style.border-left-style]="elementModel.hasBorderLeft ? elementModel.styling.borderStyle : 'none'"
+         [style.border-right-style]="elementModel.hasBorderRight ? elementModel.styling.borderStyle : 'none'">
     </div>
   `
 })
diff --git a/projects/common/components/input-elements/checkbox.component.ts b/projects/common/components/input-elements/checkbox.component.ts
index 252fc3c761049a97cac80e22e371d420f0a06bce..68b20ba0fdc47192ca0925d76b969318bf2b70ee 100644
--- a/projects/common/components/input-elements/checkbox.component.ts
+++ b/projects/common/components/input-elements/checkbox.component.ts
@@ -1,6 +1,6 @@
 import { Component, Input } from '@angular/core';
-import { FormElementComponent } from '../../directives/form-element-component.directive';
 import { CheckboxElement } from 'common/models/elements/input-elements/checkbox';
+import { FormElementComponent } from '../../directives/form-element-component.directive';
 
 @Component({
   selector: 'aspect-checkbox',
@@ -18,7 +18,7 @@ import { CheckboxElement } from 'common/models/elements/input-elements/checkbox'
                     [style.font-weight]="elementModel.styling.bold ? 'bold' : ''"
                     [style.font-style]="elementModel.styling.italic ? 'italic' : ''"
                     [style.text-decoration]="elementModel.styling.underline ? 'underline' : ''"
-                    (click)="elementModel.readOnly ? $event.preventDefault() : null">
+                    (click)="elementModel.readOnly && $event.preventDefault()">
         <div [innerHTML]="elementModel.label"></div>
       </mat-checkbox>
       <mat-error *ngIf="elementFormControl.errors && elementFormControl.touched"
diff --git a/projects/common/components/input-elements/drop-list.component.ts b/projects/common/components/input-elements/drop-list.component.ts
index 99a012af1bd983764478a32e2c3bccab41b4a115..4cb89095331dbb60b064cf78f38a09f49104885c 100644
--- a/projects/common/components/input-elements/drop-list.component.ts
+++ b/projects/common/components/input-elements/drop-list.component.ts
@@ -3,9 +3,9 @@ import { CdkDragDrop } from '@angular/cdk/drag-drop/drag-events';
 import {
   CdkDrag, CdkDropList, moveItemInArray
 } from '@angular/cdk/drag-drop';
-import { FormElementComponent } from '../../directives/form-element-component.directive';
 import { DropListElement } from 'common/models/elements/input-elements/drop-list';
 import { DragNDropValueObject } from 'common/models/elements/element';
+import { FormElementComponent } from '../../directives/form-element-component.directive';
 
 @Component({
   selector: 'aspect-drop-list',
@@ -54,7 +54,7 @@ import { DragNDropValueObject } from 'common/models/elements/element';
         </ng-container>
         <!--Leave template within the dom to ensure dragNdrop-->
         <ng-template #dropObject let-dropListValueElement let-index="index">
-          <div class="item text-item" *ngIf="!dropListValueElement.imgSrcValue"
+          <div class="item text-item" *ngIf="!dropListValueElement.imgSrc"
                [ngClass]="{ 'vertical-orientation' : elementModel.orientation === 'vertical',
                       'horizontal-orientation' : elementModel.orientation === 'horizontal'}"
                [style.background-color]="elementModel.styling.itemBackgroundColor"
@@ -64,12 +64,12 @@ import { DragNDropValueObject } from 'common/models/elements/element';
             <div *cdkDragPreview
                  [style.font-size.px]="elementModel.styling.fontSize"
                  [style.background-color]="elementModel.styling.itemBackgroundColor">
-              {{dropListValueElement.stringValue}}
+              {{dropListValueElement.text}}
             </div>
             <div class="drag-placeholder" *cdkDragPlaceholder
                  [style.min-height.px]="elementModel.styling.fontSize">
             </div>
-            {{dropListValueElement.stringValue}}
+            {{dropListValueElement.text}}
           </div>
 
           <!-- actual placeholder when item is being dragged from copy-list -->
@@ -78,11 +78,11 @@ import { DragNDropValueObject } from 'common/models/elements/element';
                [ngClass]="{ 'vertical-orientation' : elementModel.orientation === 'vertical',
                             'horizontal-orientation' : elementModel.orientation === 'horizontal'}"
                [style.background-color]="elementModel.styling.itemBackgroundColor">
-            {{dropListValueElement.stringValue}}
+            {{dropListValueElement.text}}
           </div>
 
-          <img *ngIf="dropListValueElement.imgSrcValue"
-               [src]="dropListValueElement.imgSrcValue | safeResourceUrl" alt="Image Placeholder"
+          <img *ngIf="dropListValueElement.imgSrc"
+               [src]="dropListValueElement.imgSrc | safeResourceUrl" alt="Image Placeholder"
                [style.display]="elementModel.orientation === 'flex' ? '' : 'block'"
                class="item"
                [ngClass]="{ 'vertical-orientation' : elementModel.orientation === 'vertical',
@@ -90,8 +90,8 @@ import { DragNDropValueObject } from 'common/models/elements/element';
                cdkDrag [cdkDragData]="{ element: dropListValueElement, index: index }"
                (cdkDragStarted)=dragStart(index) (cdkDragEnded)="dragEnd()"
                [style.object-fit]="'scale-down'">
-          <img *ngIf="elementModel.copyOnDrop && draggedItemIndex === index && dropListValueElement.imgSrcValue"
-               [src]="dropListValueElement.imgSrcValue | safeResourceUrl" alt="Image Placeholder"
+          <img *ngIf="elementModel.copyOnDrop && draggedItemIndex === index && dropListValueElement.imgSrc"
+               [src]="dropListValueElement.imgSrc | safeResourceUrl" alt="Image Placeholder"
                [style.display]="elementModel.orientation === 'flex' ? '' : 'block'"
                class="item"
                [ngClass]="{ 'vertical-orientation' : elementModel.orientation === 'vertical',
@@ -148,7 +148,7 @@ export class DropListComponent extends FormElementComponent {
   drop(event: CdkDragDrop<DropListComponent>): void {
     if (event.previousContainer === event.container && !event.container.data.elementModel.copyOnDrop) {
       moveItemInArray(event.container.data.elementFormControl.value as unknown as DragNDropValueObject[],
-        event.previousIndex, event.currentIndex);
+                      event.previousIndex, event.currentIndex);
       this.elementFormControl.setValue(
         (event.container.data.elementFormControl.value as DragNDropValueObject[])
       );
diff --git a/projects/common/components/input-elements/radio-button-group.component.ts b/projects/common/components/input-elements/radio-button-group.component.ts
index 2f68f7b23b6af05d937d23dd296d1655e62b43f8..542fbad7d9c7bf78d56886da2430908e55e584f8 100644
--- a/projects/common/components/input-elements/radio-button-group.component.ts
+++ b/projects/common/components/input-elements/radio-button-group.component.ts
@@ -1,6 +1,6 @@
 import { Component, Input } from '@angular/core';
-import { FormElementComponent } from '../../directives/form-element-component.directive';
 import { RadioButtonGroupElement } from 'common/models/elements/input-elements/radio-button-group';
+import { FormElementComponent } from '../../directives/form-element-component.directive';
 
 @Component({
   selector: 'aspect-radio-button-group',
@@ -23,14 +23,14 @@ import { RadioButtonGroupElement } from 'common/models/elements/input-elements/r
                        [formControl]="elementFormControl"
                        [value]="elementModel.value"
                        [style.margin-top.px]="elementModel.label !== '' ? 10 : 0">
-        <mat-radio-button *ngFor="let option of elementModel.richTextOptions; let i = index"
+        <mat-radio-button *ngFor="let option of elementModel.options; let i = index"
                           [ngClass]="{ 'strike' : elementModel.strikeOtherOptions &&
                                                   elementFormControl.value !== null &&
                                                   elementFormControl.value !== i }"
                           [value]="i"
                           [style.pointer-events]="elementModel.readOnly ? 'none' : 'unset'"
                           [style.line-height.%]="elementModel.styling.lineHeight">
-          <div class="radio-button-label" [innerHTML]="sanitizer.bypassSecurityTrustHtml(option)"></div>
+          <div class="radio-button-label" [innerHTML]="sanitizer.bypassSecurityTrustHtml(option.text)"></div>
         </mat-radio-button>
         <mat-error *ngIf="elementFormControl.errors && elementFormControl.touched"
                    class="error-message">
diff --git a/projects/common/components/input-elements/radio-group-images.component.ts b/projects/common/components/input-elements/radio-group-images.component.ts
index 73aedcc45ef36f405e4f82e2cc4ab08cd05666c6..161d30f69345df887fe1d9372698eade8c23e0ac 100644
--- a/projects/common/components/input-elements/radio-group-images.component.ts
+++ b/projects/common/components/input-elements/radio-group-images.component.ts
@@ -1,77 +1,53 @@
 import { Component, Input } from '@angular/core';
-import { FormElementComponent } from '../../directives/form-element-component.directive';
 import { RadioButtonGroupComplexElement } from 'common/models/elements/input-elements/radio-button-group-complex';
+import { FormElementComponent } from '../../directives/form-element-component.directive';
 
 @Component({
   selector: 'aspect-radio-group-images',
   template: `
-    <div [style.width.%]="100"
-         [style.height.%]="100"
-         [style.display]="'grid !important'"
-         [style.grid-template-columns]="'1fr '.repeat(elementModel.columns.length)"
-         [style.background-color]="elementModel.styling.backgroundColor"
-         [style.color]="elementModel.styling.fontColor"
-         [style.font-family]="elementModel.styling.font"
-         [style.font-size.px]="elementModel.styling.fontSize"
-         [style.font-weight]="elementModel.styling.bold ? 'bold' : ''"
-         [style.font-style]="elementModel.styling.italic ? 'italic' : ''"
-         [style.text-decoration]="elementModel.styling.underline ? 'underline' : ''">
-      <label id="radio-group-label" class="label"
-             [style.grid-column-start]="1"
-             [style.grid-column-end]="2 + elementModel.columns.length"
-             [style.grid-row-start]="1"
-             [style.grid-row-end]="2"
-             [innerHTML]="elementModel.label">
+      <label id="radio-group-label"
+              [innerHTML]="elementModel.label">
       </label>
-      <div *ngFor="let option of elementModel.columns; let i = index"
-           class="columns" fxLayout="column" fxLayoutAlign="center center"
-           [style.grid-column-start]="1 + i"
-           [style.grid-column-end]="2 + i"
-           [style.grid-row-start]="2"
-           [style.grid-row-end]="3"
-           (click)="selectOption(i)">
-        <img *ngIf="option.imgSrc && option.position === 'above'"
-             [style.object-fit]="'scale-down'"
-             [style.max-width.%]="100"
-             [src]="option.imgSrc | safeResourceUrl" alt="Image Placeholder">
-        <div [innerHTML]="sanitizer.bypassSecurityTrustHtml(option.text)"></div>
-        <img *ngIf="option.imgSrc && option.position === 'below'"
-             [style.object-fit]="'scale-down'"
-             [style.max-width.%]="100"
-             [src]="option.imgSrc | safeResourceUrl" alt="Image Placeholder">
-      </div>
       <mat-radio-group aria-labelledby="radio-group-label"
+                       [style.grid-template-columns]="elementModel.itemsPerRow !== null ?
+                                                      'repeat(' + elementModel.itemsPerRow + ', 1fr)' :
+                                                      'repeat(' + elementModel.options.length + ', 1fr)'"
                        [formControl]="elementFormControl"
-                       [style.display]="'grid'"
-                       [style.grid-template-columns]="'1fr '.repeat(elementModel.columns.length)"
-                       [style.grid-column-start]="1"
-                       [style.grid-column-end]="2 + elementModel.columns.length"
-                       [style.grid-row-start]="3"
-                       [style.grid-row-end]="4"
                        [value]="elementModel.value">
-        <mat-radio-button *ngFor="let option of elementModel.columns; let i = index"
-                          aria-labelledby="radio-group-label"
+        <mat-radio-button *ngFor="let option of elementModel.options; let i = index"
                           [style.pointer-events]="elementModel.readOnly ? 'none' : 'unset'"
-                          [value]="i"
-                          [style.grid-column-start]="1 + i"
-                          [style.grid-column-end]="2 + i"
-                          [style.grid-row-start]="1"
-                          [style.grid-row-end]="2">
+                          fxLayout="column" fxLayoutAlign="end center"
+                          [value]="i">
+          <img *ngIf="option.imgSrc && (option.imgPosition === 'above' || option.imgPosition === 'left')"
+               [style.object-fit]="'scale-down'"
+               [style.max-width.%]="100"
+               [src]="option.imgSrc | safeResourceUrl" alt="Image Placeholder">
+          <div [innerHTML]="sanitizer.bypassSecurityTrustHtml(option.text)"
+               [style.background-color]="elementModel.styling.backgroundColor"
+               [style.color]="elementModel.styling.fontColor"
+               [style.font-family]="elementModel.styling.font"
+               [style.font-size.px]="elementModel.styling.fontSize"
+               [style.font-weight]="elementModel.styling.bold ? 'bold' : ''"
+               [style.font-style]="elementModel.styling.italic ? 'italic' : ''"
+               [style.text-decoration]="elementModel.styling.underline ? 'underline' : ''"></div>
+          <img *ngIf="option.imgSrc && (option.imgPosition === 'below' || option.imgPosition === 'right')"
+               [style.object-fit]="'scale-down'"
+               [style.max-width.%]="100"
+               [src]="option.imgSrc | safeResourceUrl" alt="Image Placeholder">
         </mat-radio-button>
       </mat-radio-group>
       <mat-error *ngIf="elementFormControl.errors && elementFormControl.touched"
                  class="error-message">
         {{elementFormControl.errors | errorTransform: elementModel}}
       </mat-error>
-    </div>
   `,
   styles: [
-    '.columns {text-align: center; margin: 0 5px;}',
-    '.grid-layout .columns img {cursor: pointer;}',
-    ':host ::ng-deep mat-radio-button span.mat-radio-container {left: calc(50% - 10px)}',
-    'mat-radio-group {margin-top: 10px}',
-    '.error-message { font-size: 75% }',
-    '.grid-layout mat-radio-button {margin-top: 15px}'
+    'mat-radio-group {display: grid}',
+    ':host ::ng-deep .mat-radio-label {flex-direction: column-reverse;}',
+    ':host ::ng-deep .mat-radio-label .mat-radio-container {margin-top: 15px; margin-left: 10px;}',
+    ':host ::ng-deep .mat-radio-label .mat-radio-label-content {text-align: center;}',
+    'mat-radio-button {margin-bottom: 60px;}',
+    '.error-message { font-size: 75% }'
   ]
 })
 export class RadioGroupImagesComponent extends FormElementComponent {
diff --git a/projects/common/components/input-elements/slider.component.ts b/projects/common/components/input-elements/slider.component.ts
index a5e921e8db083a3828e622edbb15f9e7e9ea9c25..5d5fac6c4b95049a38d06f98dfd64865d33869e8 100644
--- a/projects/common/components/input-elements/slider.component.ts
+++ b/projects/common/components/input-elements/slider.component.ts
@@ -1,9 +1,6 @@
-import {
-  Component, Input, OnInit, ViewChild
-} from '@angular/core';
-import { MatSlider } from '@angular/material/slider';
-import { FormElementComponent } from '../../directives/form-element-component.directive';
+import { Component, Input } from '@angular/core';
 import { SliderElement } from 'common/models/elements/input-elements/slider';
+import { FormElementComponent } from '../../directives/form-element-component.directive';
 
 @Component({
   selector: 'aspect-slider',
@@ -76,6 +73,7 @@ import { SliderElement } from 'common/models/elements/input-elements/slider';
            [style.margin-left.px]="elementModel.barStyle ? valueMin.offsetWidth/2 - 8: valueMin.offsetWidth"
            [style.margin-top.px]="elementModel.barStyle ? -32 : -valueContainer.offsetHeight">
         <mat-slider [class]="elementModel.barStyle ? 'bar-style' : ''"
+                    [disabled]="elementModel.readOnly"
                     [thumbLabel]="elementModel.thumbLabel"
                     [formControl]="elementFormControl"
                     [style.width.%]="100"
@@ -95,23 +93,13 @@ import { SliderElement } from 'common/models/elements/input-elements/slider';
     '.value-container-min {min-width: 8px}',
     '.arrow-line {height: 2px; width: 100%; background-color: #555;}',
     '.number-marker {width: 2px; height: 20px; background-color: #555; margin: 10px auto 0 auto}',
-    // eslint-disable-next-line max-len
     '.arrow-head {width: 0; height: 0; border-top: 8px solid transparent; border-bottom: 8px solid transparent; border-left: 20px solid #555;}',
     // Background color must use !important to be displayed also in the editor
-    // eslint-disable-next-line max-len
     ':host ::ng-deep .bar-style .mat-slider-thumb {border-radius: 0; border: none; width: 9px; height: 40px; bottom: -20px; margin-right: 5px; background-color: #006064 !important}',
     ':host ::ng-deep .bar-style .mat-slider-track-fill {background-color: rgba(0,0,0,0);}',
     ':host ::ng-deep .bar-style .mat-slider-track-background {background-color: rgba(0,0,0,0);}'
   ]
 })
-export class SliderComponent extends FormElementComponent implements OnInit {
-  @ViewChild(MatSlider) inputElement!: MatSlider;
+export class SliderComponent extends FormElementComponent {
   @Input() elementModel!: SliderElement;
-
-  ngOnInit(): void {
-    super.ngOnInit();
-    if (this.inputElement) {
-      this.inputElement.disabled = this.elementModel.readOnly as boolean;
-    }
-  }
 }
diff --git a/projects/common/components/input-elements/text-area.component.ts b/projects/common/components/input-elements/text-area.component.ts
index 257ae1c6655fdb113f2afba04f83ac5b6c0a0328..05670801d691c783b9c54547ccc9113ea8e14368 100644
--- a/projects/common/components/input-elements/text-area.component.ts
+++ b/projects/common/components/input-elements/text-area.component.ts
@@ -1,8 +1,8 @@
 import {
   Component, Output, EventEmitter, Input
 } from '@angular/core';
-import { FormElementComponent } from '../../directives/form-element-component.directive';
 import { TextAreaElement } from 'common/models/elements/input-elements/text-area';
+import { FormElementComponent } from '../../directives/form-element-component.directive';
 
 @Component({
   selector: 'aspect-text-area',
diff --git a/projects/common/components/media-elements/media-player-control-bar/media-player-control-bar.component.ts b/projects/common/components/media-elements/media-player-control-bar/media-player-control-bar.component.ts
index 6796b9e14d3db07749f6b6edace8424fb6887dae..196b04f2069b6edc9bc96636c26d2dcd818e0111 100644
--- a/projects/common/components/media-elements/media-player-control-bar/media-player-control-bar.component.ts
+++ b/projects/common/components/media-elements/media-player-control-bar/media-player-control-bar.component.ts
@@ -3,6 +3,10 @@ import {
 } from '@angular/core';
 import { MatSliderChange } from '@angular/material/slider';
 import { PlayerProperties, ValueChangeElement } from 'common/models/elements/element';
+import {
+  fromEvent, Subject, tap, throttleTime
+} from 'rxjs';
+import { takeUntil } from 'rxjs/operators';
 
 @Component({
   selector: 'aspect-media-player-control-bar',
@@ -34,16 +38,23 @@ export class MediaPlayerControlBarComponent implements OnInit, OnChanges, OnDest
   playbackTime: number = 0;
   valid: boolean = false;
 
+  private ngUnsubscribe = new Subject<void>();
+
   ngOnInit(): void {
     this.playbackTime = this.savedPlaybackTime || this.playerProperties.playbackTime;
     this.started = this.playbackTime > 0;
     this.runCounter = Math.floor(this.playbackTime);
     this.player.ondurationchange = () => this.initTimeValues();
-    this.player.ontimeupdate = () => {
-      this.currentTime = this.player.currentTime / 60;
-      this.currentRestTime = this.player.duration ? (this.player.duration - this.player.currentTime) / 60 : 0;
-      this.sendPlaybackTimeChanged();
-    };
+    fromEvent(this.player, 'timeupdate')
+      .pipe(
+        takeUntil(this.ngUnsubscribe),
+        tap(() => {
+          this.currentTime = this.player.currentTime / 60;
+          this.currentRestTime = this.player.duration ? (this.player.duration - this.player.currentTime) / 60 : 0;
+        }),
+        throttleTime(5000)
+      )
+      .subscribe(() => this.sendPlaybackTimeChanged());
     this.player.onpause = () => {
       this.playing = false;
       this.pausing = true;
@@ -186,5 +197,7 @@ export class MediaPlayerControlBarComponent implements OnInit, OnChanges, OnDest
 
   ngOnDestroy(): void {
     this.player.pause();
+    this.ngUnsubscribe.next();
+    this.ngUnsubscribe.complete();
   }
 }
diff --git a/projects/common/directives/media-player-element-component.directive.ts b/projects/common/directives/media-player-element-component.directive.ts
index de525feb42cbab1cd0df6b466e762da5a3602e39..812567cdacc216ac27978cf81e878165ba98eee4 100644
--- a/projects/common/directives/media-player-element-component.directive.ts
+++ b/projects/common/directives/media-player-element-component.directive.ts
@@ -3,10 +3,10 @@ import {
 } from '@angular/core';
 import { Subject } from 'rxjs';
 import { takeUntil } from 'rxjs/operators';
-import { ElementComponent } from './element-component.directive';
 import { AudioElement } from 'common/models/elements/media-elements/audio';
 import { VideoElement } from 'common/models/elements/media-elements/video';
 import { ValueChangeElement } from 'common/models/elements/element';
+import { ElementComponent } from './element-component.directive';
 
 @Directive()
 export abstract class MediaPlayerElementComponent extends ElementComponent implements OnInit, OnDestroy {
diff --git a/projects/common/models/elements/button/button.ts b/projects/common/models/elements/button/button.ts
index a97786f59a6f6764e8891a7eaa7e5b59517293ff..4b44a4cc2c79e14acb660667ef62c04f9c781592 100644
--- a/projects/common/models/elements/button/button.ts
+++ b/projects/common/models/elements/button/button.ts
@@ -1,6 +1,8 @@
 import { Type } from '@angular/core';
 import { ElementFactory } from 'common/util/element.factory';
-import { BasicStyles, PositionedUIElement, PositionProperties, UIElement } from 'common/models/elements/element';
+import {
+  BasicStyles, PositionedUIElement, PositionProperties, UIElement
+} from 'common/models/elements/element';
 import { ButtonComponent } from 'common/components/button/button.component';
 import { ElementComponent } from 'common/directives/element-component.directive';
 
@@ -28,7 +30,7 @@ export class ButtonElement extends UIElement implements PositionedUIElement {
     };
   }
 
-  getComponentFactory(): Type<ElementComponent> {
+  getElementComponent(): Type<ElementComponent> {
     return ButtonComponent;
   }
 }
diff --git a/projects/common/models/elements/compound-elements/cloze/cloze-child-elements/drop-list-simple.ts b/projects/common/models/elements/compound-elements/cloze/cloze-child-elements/drop-list-simple.ts
index cc50c783c1e7f993fcc8dbe0b36ef5a7b52217da..dc42abf27ffec836172725387e9b94200d0d29b4 100644
--- a/projects/common/models/elements/compound-elements/cloze/cloze-child-elements/drop-list-simple.ts
+++ b/projects/common/models/elements/compound-elements/cloze/cloze-child-elements/drop-list-simple.ts
@@ -1,9 +1,6 @@
 import { ElementFactory } from 'common/util/element.factory';
 import {
-  BasicStyles,
-  DragNDropValueObject,
-  InputElement,
-  AnswerScheme,
+  BasicStyles, DragNDropValueObject, InputElement, UIElementValue,  AnswerScheme,
   AnswerSchemeValue
 } from 'common/models/elements/element';
 import { Type } from '@angular/core';
@@ -11,9 +8,11 @@ import { ElementComponent } from 'common/directives/element-component.directive'
 import {
   DropListSimpleComponent
 } from 'common/components/compound-elements/cloze/cloze-child-elements/drop-list-simple.component';
+import { IDManager } from 'common/util/id-manager';
 import { DropListElement } from 'common/models/elements/input-elements/drop-list';
 
 export class DropListSimpleElement extends InputElement {
+  value: DragNDropValueObject[] = [];
   connectedTo: string[] = [];
   copyOnDrop: boolean = false;
   highlightReceivingDropList: boolean = false;
@@ -24,16 +23,21 @@ export class DropListSimpleElement extends InputElement {
 
   constructor(element: Partial<DropListSimpleElement>, ...args: unknown[]) {
     super({ width: 150, height: 30, ...element }, ...args);
-    this.value = element.value || [];
+    if (element.value) {
+      this.value = DropListSimpleElement.checkAndRepairValueIDs(element.value);
+    }
     if (element.connectedTo) this.connectedTo = element.connectedTo;
     if (element.copyOnDrop) this.copyOnDrop = element.copyOnDrop;
     if (element.highlightReceivingDropList) this.highlightReceivingDropList = element.highlightReceivingDropList;
-    if (element.highlightReceivingDropListColor) this.highlightReceivingDropListColor = element.highlightReceivingDropListColor;
+    if (element.highlightReceivingDropListColor) {
+      this.highlightReceivingDropListColor = element.highlightReceivingDropListColor;
+    }
     this.styling = {
       ...ElementFactory.initStylingProps({
         backgroundColor: '#f4f4f2',
         itemBackgroundColor: '#c9e0e0',
-        ...element.styling })
+        ...element.styling
+      })
     };
   }
 
@@ -61,7 +65,26 @@ export class DropListSimpleElement extends InputElement {
       .map(option => ({ value: option.id, label: option.stringValue as string })); // TODO: imageValueSrc
   }
 
-  getComponentFactory(): Type<ElementComponent> {
+  setProperty(property: string, value: UIElementValue) {
+    if (property === 'value') {
+      this.value = DropListSimpleElement.checkAndRepairValueIDs(value as DragNDropValueObject[]);
+    } else {
+      super.setProperty(property, value);
+    }
+  }
+
+  private static checkAndRepairValueIDs(valueList: DragNDropValueObject[]): DragNDropValueObject[] {
+    valueList.forEach(valueObject => {
+      if (IDManager.getInstance().isIdAvailable(valueObject.id)) {
+        IDManager.getInstance().addID(valueObject.id);
+      } else {
+        valueObject.id = IDManager.getInstance().getNewID('value');
+      }
+    });
+    return valueList;
+  }
+
+  getElementComponent(): Type<ElementComponent> {
     return DropListSimpleComponent;
   }
 }
diff --git a/projects/common/models/elements/compound-elements/cloze/cloze-child-elements/text-field-simple.ts b/projects/common/models/elements/compound-elements/cloze/cloze-child-elements/text-field-simple.ts
index 4abc32a4b8209742822bcf76c4826fdc70801a0e..cdce6dd3a0a9e9b9b6668ef83c0aecdd670ffcae 100644
--- a/projects/common/models/elements/compound-elements/cloze/cloze-child-elements/text-field-simple.ts
+++ b/projects/common/models/elements/compound-elements/cloze/cloze-child-elements/text-field-simple.ts
@@ -62,7 +62,7 @@ export class TextFieldSimpleElement extends InputElement {
     };
   }
 
-  getComponentFactory(): Type<ElementComponent> {
+  getElementComponent(): Type<ElementComponent> {
     return TextFieldSimpleComponent;
   }
 }
diff --git a/projects/common/models/elements/compound-elements/cloze/cloze-child-elements/toggle-button.ts b/projects/common/models/elements/compound-elements/cloze/cloze-child-elements/toggle-button.ts
index 08c9889b8d19c48ec3f7022f26d5b00aa296e78e..185b4b2e2d9dc01187229f6084ae72e114ba6937 100644
--- a/projects/common/models/elements/compound-elements/cloze/cloze-child-elements/toggle-button.ts
+++ b/projects/common/models/elements/compound-elements/cloze/cloze-child-elements/toggle-button.ts
@@ -9,6 +9,7 @@ import {
 export class ToggleButtonElement extends InputElement {
   richTextOptions: string[] = [];
   strikeOtherOptions: boolean = false;
+  strikeSelectedOption: boolean = false;
   verticalOrientation: boolean = false;
   dynamicWidth: boolean = true;
   styling: BasicStyles & {
@@ -20,6 +21,7 @@ export class ToggleButtonElement extends InputElement {
     super({ height: 25, ...element }, ...args);
     if (element.richTextOptions) this.richTextOptions = element.richTextOptions;
     if (element.strikeOtherOptions) this.strikeOtherOptions = element.strikeOtherOptions;
+    if (element.strikeSelectedOption) this.strikeSelectedOption = element.strikeSelectedOption;
     if (element.verticalOrientation) this.verticalOrientation = element.verticalOrientation;
     if (element.dynamicWidth !== undefined) this.dynamicWidth = element.dynamicWidth;
     this.styling = {
@@ -53,7 +55,7 @@ export class ToggleButtonElement extends InputElement {
       .map((option, index) => ({ value: (index + 1).toString(), label: option }));
   }
 
-  getComponentFactory(): Type<ElementComponent> {
+  getElementComponent(): Type<ElementComponent> {
     return ToggleButtonComponent;
   }
 }
diff --git a/projects/common/models/elements/compound-elements/cloze/cloze.ts b/projects/common/models/elements/compound-elements/cloze/cloze.ts
index a90b6dc5b5b6f3146208bbea07b4230f32131655..882ef90946bd1c9d98b53f64c73f5a0757fb0c0a 100644
--- a/projects/common/models/elements/compound-elements/cloze/cloze.ts
+++ b/projects/common/models/elements/compound-elements/cloze/cloze.ts
@@ -40,7 +40,6 @@ export class ClozeElement extends CompoundElement implements PositionedUIElement
   setProperty(property: string, value: UIElementValue): void {
     if (property === 'document') {
       this.document = value as ClozeDocument;
-
       this.document.content.forEach((node: any) => {
         if (node.type === 'paragraph' || node.type === 'heading') {
           ClozeElement.createSubNodeElements(node);
@@ -56,7 +55,6 @@ export class ClozeElement extends CompoundElement implements PositionedUIElement
           });
         }
       });
-
     } else {
       super.setProperty(property, value);
     }
@@ -76,10 +74,11 @@ export class ClozeElement extends CompoundElement implements PositionedUIElement
   private initDocument(element: Partial<ClozeElement>, idManager?: IDManager): ClozeDocument {
     return {
       ...element.document,
+      type: 'doc',
       content: element.document?.content ? element.document.content
         .map((paragraph: ClozeDocumentParagraph) => ({
           ...paragraph,
-          content: paragraph.content
+          content: paragraph.content ? paragraph.content
             .map((paraPart: ClozeDocumentParagraphPart) => (
               ['TextField', 'DropList', 'ToggleButton'].includes(paraPart.type) ?
                 {
@@ -92,12 +91,27 @@ export class ClozeElement extends CompoundElement implements PositionedUIElement
                 {
                   ...paraPart
                 }
-            ))
-        })) : []
+            )) : undefined
+        })) : [{
+        type: 'paragraph',
+        attrs: {
+          textAlign: 'left',
+          indent: null,
+          indentSize: 20,
+          hangingIndent: false,
+          margin: 0
+        },
+        content: [
+          {
+            text: 'Lorem Ipsum',
+            type: 'text'
+          }
+        ]
+      }]
     } as ClozeDocument;
   }
 
-  getComponentFactory(): Type<ElementComponent> {
+  getElementComponent(): Type<ElementComponent> {
     return ClozeComponent;
   }
 
diff --git a/projects/common/models/elements/compound-elements/likert/likert-row.ts b/projects/common/models/elements/compound-elements/likert/likert-row.ts
index 09009d38c7fa6a5dab9bdf18738308e3eb0942b6..32d132be77b79101ab42c904d549efd4473b6c7e 100644
--- a/projects/common/models/elements/compound-elements/likert/likert-row.ts
+++ b/projects/common/models/elements/compound-elements/likert/likert-row.ts
@@ -6,14 +6,14 @@ import {
 } from 'common/components/compound-elements/likert/likert-radio-button-group.component';
 
 export class LikertRowElement extends InputElement {
-  rowLabel: TextImageLabel = { text: '', imgSrc: null, position: 'above' };
+  rowLabel: TextImageLabel = { text: '', imgSrc: null, imgPosition: 'above' };
   columnCount: number = 0;
   firstColumnSizeRatio: number = 5;
   verticalButtonAlignment: 'auto' | 'center' = 'center';
 
   constructor(element: Partial<LikertRowElement>, ...args: unknown[]) {
     super(element, ...args);
-    if (element.rowLabel) this.rowLabel = element.rowLabel;
+    if (element.rowLabel) this.rowLabel = { ...element.rowLabel };
     if (element.columnCount) this.columnCount = element.columnCount;
     if (element.firstColumnSizeRatio) this.firstColumnSizeRatio = element.firstColumnSizeRatio;
     if (element.verticalButtonAlignment) this.verticalButtonAlignment = element.verticalButtonAlignment;
@@ -43,7 +43,7 @@ export class LikertRowElement extends InputElement {
     ];
   }
 
-  getComponentFactory(): Type<ElementComponent> {
+  getElementComponent(): Type<ElementComponent> {
     return LikertRadioButtonGroupComponent;
   }
 }
diff --git a/projects/common/models/elements/compound-elements/likert/likert.ts b/projects/common/models/elements/compound-elements/likert/likert.ts
index 076ad6d8c76cad39d8d4ccafada6d971944196f7..349c079dee8a973a58cb9c67b20fde0a6f206a89 100644
--- a/projects/common/models/elements/compound-elements/likert/likert.ts
+++ b/projects/common/models/elements/compound-elements/likert/likert.ts
@@ -2,16 +2,18 @@ import { Type } from '@angular/core';
 import { ElementFactory } from 'common/util/element.factory';
 import {
   BasicStyles, CompoundElement, UIElement,
-  PositionedUIElement, PositionProperties, TextImageLabel
+  PositionedUIElement, PositionProperties, UIElementValue, TextImageLabel, OptionElement
 } from 'common/models/elements/element';
 import { LikertRowElement } from 'common/models/elements/compound-elements/likert/likert-row';
 import { ElementComponent } from 'common/directives/element-component.directive';
 import { LikertComponent } from 'common/components/compound-elements/likert/likert.component';
 
-export class LikertElement extends CompoundElement implements PositionedUIElement {
+export class LikertElement extends CompoundElement implements PositionedUIElement, OptionElement {
   rows: LikertRowElement[] = [];
-  columns: TextImageLabel[] = [];
+  options: TextImageLabel[] = [];
   firstColumnSizeRatio: number = 5;
+  label: string = 'Optionentabelle Beschriftung';
+  label2: string = 'Beschriftung Erste Spalte';
   position: PositionProperties;
   styling: BasicStyles & {
     lineHeight: number;
@@ -21,9 +23,11 @@ export class LikertElement extends CompoundElement implements PositionedUIElemen
 
   constructor(element: Partial<LikertElement>, ...args: unknown[]) {
     super({ width: 250, height: 200, ...element }, ...args);
-    if (element.columns) this.columns = element.columns;
+    if (element.options) this.options = [...element.options];
     if (element.firstColumnSizeRatio) this.firstColumnSizeRatio = element.firstColumnSizeRatio;
     this.rows = element.rows !== undefined ? element.rows?.map(row => new LikertRowElement(row, ...args)) : [];
+    this.label = element.label !== undefined ? element.label : 'Optionentabelle Beschriftung';
+    this.label2 = element.label2 !== undefined ? element.label2 : 'Optionentabelle Erste Spalte';
     this.position = ElementFactory.initPositionProps(element.position);
     this.styling = {
       ...ElementFactory.initStylingProps({
@@ -36,7 +40,24 @@ export class LikertElement extends CompoundElement implements PositionedUIElemen
     };
   }
 
-  getComponentFactory(): Type<ElementComponent> {
+  getNewOptionLabel(optionText: string): TextImageLabel {
+    return ElementFactory.createOptionLabel(optionText, true) as TextImageLabel;
+  }
+
+  setProperty(property: string, value: UIElementValue): void {
+    super.setProperty(property, value);
+    if (property === 'rows') {
+      this.rows = value as LikertRowElement[];
+    }
+    if (property === 'options') {
+      this.getChildElements().forEach(childElement => childElement.setProperty('columnCount', this.options.length));
+    }
+    if (property === 'readOnly') {
+      this.getChildElements().forEach(childElement => childElement.setProperty('readOnly', value));
+    }
+  }
+
+  getElementComponent(): Type<ElementComponent> {
     return LikertComponent;
   }
 
diff --git a/projects/common/models/elements/element.ts b/projects/common/models/elements/element.ts
index 89828479776ce66b25e535fffaacc5f203430506..509e778bfbb3560b477ca6ab670c01f46175985d 100644
--- a/projects/common/models/elements/element.ts
+++ b/projects/common/models/elements/element.ts
@@ -1,15 +1,17 @@
+// eslint-disable-next-line max-classes-per-file
 import { ElementComponent } from 'common/directives/element-component.directive';
 import { Type } from '@angular/core';
 import { ClozeDocument } from 'common/models/elements/compound-elements/cloze/cloze';
 import { ElementFactory } from 'common/util/element.factory';
 import { IDManager } from 'common/util/id-manager';
+import { LikertRowElement } from 'common/models/elements/compound-elements/likert/likert-row';
 
 export type UIElementType = 'text' | 'button' | 'text-field' | 'text-field-simple' | 'text-area' | 'checkbox'
 | 'dropdown' | 'radio' | 'image' | 'audio' | 'video' | 'likert' | 'likert-row' | 'radio-group-images'
 | 'drop-list' | 'drop-list-simple' | 'cloze' | 'spell-correct' | 'slider' | 'frame' | 'toggle-button';
 
 export type UIElementValue = string | number | boolean | undefined | UIElementType | InputElementValue |
-TextImageLabel[] | ClozeDocument | TextImageLabel |
+TextLabel | TextLabel[] | ClozeDocument | LikertRowElement[] |
 PositionProperties | PlayerProperties | BasicStyles;
 
 export type InputAssistancePreset = null | 'french' | 'numbers' | 'numbersAndOperators' | 'numbersAndBasicOperators'
@@ -75,9 +77,10 @@ export abstract class UIElement {
   }
 
   abstract getComponentFactory(): Type<ElementComponent>;
+  abstract getElementComponent(): Type<ElementComponent>;
 }
 
-export type InputElementValue = string[] | string | number | boolean | DragNDropValueObject[] | null;
+export type InputElementValue = string[] | string | number | boolean | TextLabel[] | null;
 
 export abstract class InputElement extends UIElement {
   label: string = 'Beschriftung';
@@ -222,14 +225,21 @@ export interface ValueChangeElement {
   value: InputElementValue;
 }
 
-export interface TextImageLabel {
+export interface OptionElement extends UIElement {
+  getNewOptionLabel(optionText: string): Label;
+}
+
+export interface TextLabel {
   text: string;
+}
+
+export interface TextImageLabel extends TextLabel {
   imgSrc: string | null;
-  position: 'above' | 'below' | 'left' | 'right';
+  imgPosition: 'above' | 'below' | 'left' | 'right';
 }
 
-export type DragNDropValueObject = {
+export interface DragNDropValueObject extends TextImageLabel {
   id: string;
-  stringValue?: string;
-  imgSrcValue?: string;
-};
+}
+
+export type Label = TextLabel | TextImageLabel | DragNDropValueObject;
diff --git a/projects/common/models/elements/frame/frame.ts b/projects/common/models/elements/frame/frame.ts
index 5a63eafeff14fbb031b76753d97b77cfdb196190..371dd50d10911ab84002147e77d98928158d5dfa 100644
--- a/projects/common/models/elements/frame/frame.ts
+++ b/projects/common/models/elements/frame/frame.ts
@@ -1,10 +1,17 @@
 import { Type } from '@angular/core';
 import { ElementFactory } from 'common/util/element.factory';
-import { BasicStyles, PositionedUIElement, PositionProperties, UIElement } from 'common/models/elements/element';
+import {
+  BasicStyles, PositionedUIElement, PositionProperties, UIElement
+} from 'common/models/elements/element';
 import { FrameComponent } from 'common/components/frame/frame.component';
 import { ElementComponent } from 'common/directives/element-component.directive';
 
 export class FrameElement extends UIElement implements PositionedUIElement {
+  hasBorderTop: boolean = true;
+  hasBorderBottom: boolean = true;
+  hasBorderLeft: boolean = true;
+  hasBorderRight: boolean = true;
+
   position: PositionProperties;
   styling: BasicStyles & {
     borderWidth: number;
@@ -22,13 +29,13 @@ export class FrameElement extends UIElement implements PositionedUIElement {
         borderWidth: 1,
         borderColor: 'black',
         borderStyle: 'solid',
-        borderRadius:  0,
+        borderRadius: 0,
         ...element.styling
       })
     };
   }
 
-  getComponentFactory(): Type<ElementComponent> {
+  getElementComponent(): Type<ElementComponent> {
     return FrameComponent;
   }
 }
diff --git a/projects/common/models/elements/input-elements/checkbox.ts b/projects/common/models/elements/input-elements/checkbox.ts
index aa820b603f78d1310f73375e837c0e39dc74f0d5..cd4136357b5a85d6775a93f6c5698e210d6ac439 100644
--- a/projects/common/models/elements/input-elements/checkbox.ts
+++ b/projects/common/models/elements/input-elements/checkbox.ts
@@ -1,12 +1,6 @@
 import { Type } from '@angular/core';
 import { ElementFactory } from 'common/util/element.factory';
-import {
-  BasicStyles,
-  InputElement,
-  PositionedUIElement,
-  PositionProperties,
-  AnswerScheme, AnswerSchemeValue
-} from 'common/models/elements/element';
+import { BasicStyles, InputElement, PositionedUIElement, PositionProperties, AnswerScheme, AnswerSchemeValue } from 'common/models/elements/element';
 import { ElementComponent } from 'common/directives/element-component.directive';
 import { CheckboxComponent } from 'common/components/input-elements/checkbox.component';
 
@@ -43,7 +37,7 @@ export class CheckboxElement extends InputElement implements PositionedUIElement
     ];
   }
 
-  getComponentFactory(): Type<ElementComponent> {
+  getElementComponent(): Type<ElementComponent> {
     return CheckboxComponent;
   }
 }
diff --git a/projects/common/models/elements/input-elements/drop-list.ts b/projects/common/models/elements/input-elements/drop-list.ts
index 9cb089f7e66a81bc1427d246a9c820d8de1a1fb4..43d63b33295ee2060b5b82bc72cb813d818be953 100644
--- a/projects/common/models/elements/input-elements/drop-list.ts
+++ b/projects/common/models/elements/input-elements/drop-list.ts
@@ -3,7 +3,8 @@ import { ElementFactory } from 'common/util/element.factory';
 import {
   InputElement, PositionedUIElement,
   DragNDropValueObject,
-  BasicStyles, PositionProperties, AnswerScheme, AnswerSchemeValue
+  BasicStyles, PositionProperties,
+  AnswerScheme, AnswerSchemeValue
 } from 'common/models/elements/element';
 import { ElementComponent } from 'common/directives/element-component.directive';
 import { DropListComponent } from 'common/components/input-elements/drop-list.component';
@@ -13,6 +14,7 @@ import {
 } from 'common/models/elements/compound-elements/cloze/cloze-child-elements/drop-list-simple';
 
 export class DropListElement extends InputElement implements PositionedUIElement {
+  value: DragNDropValueObject[];
   onlyOneItem: boolean = false;
   connectedTo: string[] = [];
   copyOnDrop: boolean = false;
@@ -35,8 +37,9 @@ export class DropListElement extends InputElement implements PositionedUIElement
     if (element.copyOnDrop) this.copyOnDrop = element.copyOnDrop;
     if (element.orientation) this.orientation = element.orientation;
     if (element.highlightReceivingDropList) this.highlightReceivingDropList = element.highlightReceivingDropList;
-    if (element.highlightReceivingDropListColor) this.highlightReceivingDropListColor =
-      element.highlightReceivingDropListColor;
+    if (element.highlightReceivingDropListColor) {
+      this.highlightReceivingDropListColor = element.highlightReceivingDropListColor;
+    }
     this.position = ElementFactory.initPositionProps({ useMinHeight: true, ...element.position });
     this.styling = {
       ...ElementFactory.initStylingProps({
@@ -78,7 +81,7 @@ export class DropListElement extends InputElement implements PositionedUIElement
     return (!this.connectedTo.length && (this.value as DragNDropValueObject[]).length > 1);
   }
 
-  getComponentFactory(): Type<ElementComponent> {
+  getElementComponent(): Type<ElementComponent> {
     return DropListComponent;
   }
 }
diff --git a/projects/common/models/elements/input-elements/dropdown.ts b/projects/common/models/elements/input-elements/dropdown.ts
index ab1ece7b2f9473d47333fb1dabef0419b945deb7..234c1921fec2198ea487dac69f97d5d0b58fce07 100644
--- a/projects/common/models/elements/input-elements/dropdown.ts
+++ b/projects/common/models/elements/input-elements/dropdown.ts
@@ -1,24 +1,21 @@
 import { Type } from '@angular/core';
 import { ElementFactory } from 'common/util/element.factory';
 import {
-  BasicStyles,
-  InputElement,
-  PositionedUIElement,
-  PositionProperties,
+  BasicStyles, InputElement, TextLabel, PositionedUIElement, PositionProperties, OptionElement,
   AnswerScheme, AnswerSchemeValue
 } from 'common/models/elements/element';
 import { ElementComponent } from 'common/directives/element-component.directive';
 import { DropdownComponent } from 'common/components/input-elements/dropdown.component';
 
-export class DropdownElement extends InputElement implements PositionedUIElement {
-  options: string[] = [];
+export class DropdownElement extends InputElement implements PositionedUIElement, OptionElement {
+  options: TextLabel[] = [];
   allowUnset: boolean = false;
   position: PositionProperties;
   styling: BasicStyles;
 
   constructor(element: Partial<DropdownElement>, ...args: unknown[]) {
     super({ width: 240, height: 83, ...element }, ...args);
-    if (element.options) this.options = element.options;
+    if (element.options) this.options = [...element.options];
     if (element.allowUnset) this.allowUnset = element.allowUnset;
     this.position = ElementFactory.initPositionProps(element.position);
     this.styling = {
@@ -46,7 +43,11 @@ export class DropdownElement extends InputElement implements PositionedUIElement
     return this.options.map((option, index) => ({ value: (index + 1).toString(), label: option }));
   }
 
-  getComponentFactory(): Type<ElementComponent> {
+  getElementComponent(): Type<ElementComponent> {
     return DropdownComponent;
   }
+
+  getNewOptionLabel(optionText: string): TextLabel {
+    return ElementFactory.createOptionLabel(optionText) as TextLabel;
+  }
 }
diff --git a/projects/common/models/elements/input-elements/radio-button-group-complex.ts b/projects/common/models/elements/input-elements/radio-button-group-complex.ts
index 4b147d993854b2ed65ac58b215a5cf66ba5b2aa4..d31bbc7c7092a231794afd71eb6cd4b098d6e7ef 100644
--- a/projects/common/models/elements/input-elements/radio-button-group-complex.ts
+++ b/projects/common/models/elements/input-elements/radio-button-group-complex.ts
@@ -1,23 +1,23 @@
 import { Type } from '@angular/core';
 import { ElementFactory } from 'common/util/element.factory';
 import {
-  BasicStyles,
-  InputElement,
-  PositionedUIElement,
-  PositionProperties, AnswerScheme, AnswerSchemeValue,
-  TextImageLabel
+  BasicStyles, InputElement, OptionElement,
+  PositionedUIElement, PositionProperties, TextImageLabel,
+  AnswerScheme, AnswerSchemeValue,
 } from 'common/models/elements/element';
 import { ElementComponent } from 'common/directives/element-component.directive';
 import { RadioGroupImagesComponent } from 'common/components/input-elements/radio-group-images.component';
 
-export class RadioButtonGroupComplexElement extends InputElement implements PositionedUIElement {
-  columns: TextImageLabel[] = [];
+export class RadioButtonGroupComplexElement extends InputElement implements PositionedUIElement, OptionElement {
+  options: TextImageLabel[] = [];
+  itemsPerRow: number | null;
   position: PositionProperties;
   styling: BasicStyles;
 
   constructor(element: Partial<RadioButtonGroupComplexElement>, ...args: unknown[]) {
     super({ height: 100, ...element }, ...args);
-    if (element.columns) this.columns = element.columns;
+    if (element.options) this.options = [...element.options];
+    this.itemsPerRow = element.itemsPerRow !== undefined ? element.itemsPerRow : null;
     this.position = ElementFactory.initPositionProps({ marginBottom: 40, ...element.position });
     this.styling = {
       ...ElementFactory.initStylingProps({ backgroundColor: 'transparent', ...element.styling })
@@ -45,7 +45,11 @@ export class RadioButtonGroupComplexElement extends InputElement implements Posi
       .map((option, index) => ({ value: (index + 1).toString(), label: option.text })); //TODO iMAGE
   }
 
-  getComponentFactory(): Type<ElementComponent> {
+  getElementComponent(): Type<ElementComponent> {
     return RadioGroupImagesComponent;
   }
+
+  getNewOptionLabel(optionText: string): TextImageLabel {
+    return ElementFactory.createOptionLabel(optionText, true) as TextImageLabel;
+  }
 }
diff --git a/projects/common/models/elements/input-elements/radio-button-group.ts b/projects/common/models/elements/input-elements/radio-button-group.ts
index a97c5c4f79a3f84c73431aa8c30aa5a9c76c92f6..89e555c612312016e0cdfb4ab330826de24ffc04 100644
--- a/projects/common/models/elements/input-elements/radio-button-group.ts
+++ b/projects/common/models/elements/input-elements/radio-button-group.ts
@@ -1,17 +1,14 @@
 import { Type } from '@angular/core';
 import { ElementFactory } from 'common/util/element.factory';
 import {
-  BasicStyles,
-  InputElement,
-  PositionedUIElement,
-  PositionProperties,
+  BasicStyles, InputElement, TextLabel, PositionedUIElement, PositionProperties, OptionElement,
   AnswerScheme, AnswerSchemeValue
 } from 'common/models/elements/element';
 import { ElementComponent } from 'common/directives/element-component.directive';
 import { RadioButtonGroupComponent } from 'common/components/input-elements/radio-button-group.component';
 
-export class RadioButtonGroupElement extends InputElement implements PositionedUIElement {
-  richTextOptions: string[] = [];
+export class RadioButtonGroupElement extends InputElement implements PositionedUIElement, OptionElement {
+  options: TextLabel[] = [];
   alignment: 'column' | 'row' = 'column';
   strikeOtherOptions: boolean = false;
   position: PositionProperties;
@@ -21,9 +18,12 @@ export class RadioButtonGroupElement extends InputElement implements PositionedU
 
   constructor(element: Partial<RadioButtonGroupElement>, ...args: unknown[]) {
     super({ height: 100, ...element }, ...args);
-    if (element.richTextOptions) this.richTextOptions = element.richTextOptions;
+    if (element.options) this.options = [...element.options];
     if (element.alignment) this.alignment = element.alignment;
     if (element.strikeOtherOptions) this.strikeOtherOptions = element.strikeOtherOptions;
+
+    this.value = element.value !== undefined ? element.value : [];
+
     this.position = ElementFactory.initPositionProps({ marginBottom: 30, ...element.position });
     this.styling = {
       ...ElementFactory.initStylingProps({
@@ -55,7 +55,11 @@ export class RadioButtonGroupElement extends InputElement implements PositionedU
       .map((option, index) => ({ value: (index + 1).toString(), label: option }));
   }
 
-  getComponentFactory(): Type<ElementComponent> {
+  getElementComponent(): Type<ElementComponent> {
     return RadioButtonGroupComponent;
   }
+
+  getNewOptionLabel(optionText: string): TextLabel {
+    return ElementFactory.createOptionLabel(optionText) as TextLabel;
+  }
 }
diff --git a/projects/common/models/elements/input-elements/slider.ts b/projects/common/models/elements/input-elements/slider.ts
index 756f989a426a9bc9f95a27e24f8fdd3e671ea9ef..8cd2ceb5ba191fbd35fb675124279192260d5600 100644
--- a/projects/common/models/elements/input-elements/slider.ts
+++ b/projects/common/models/elements/input-elements/slider.ts
@@ -1,11 +1,7 @@
 import { Type } from '@angular/core';
 import { ElementFactory } from 'common/util/element.factory';
 import {
-  BasicStyles,
-  InputElement,
-  PositionedUIElement,
-  PositionProperties,
-  AnswerScheme, AnswerSchemeValue
+  BasicStyles, InputElement, PositionedUIElement, PositionProperties, AnswerScheme, AnswerSchemeValue
 } from 'common/models/elements/element';
 import { ElementComponent } from 'common/directives/element-component.directive';
 import { SliderComponent } from 'common/components/input-elements/slider.component';
@@ -60,7 +56,7 @@ export class SliderElement extends InputElement implements PositionedUIElement {
     )) as AnswerSchemeValue[];
   }
 
-  getComponentFactory(): Type<ElementComponent> {
+  getElementComponent(): Type<ElementComponent> {
     return SliderComponent;
   }
 }
diff --git a/projects/common/models/elements/input-elements/spell-correct.ts b/projects/common/models/elements/input-elements/spell-correct.ts
index 219a1585a4cbfe634b2ede5a73481e488cd15eeb..7b18ae065ed41540142ac2584107ab340bbfc0f9 100644
--- a/projects/common/models/elements/input-elements/spell-correct.ts
+++ b/projects/common/models/elements/input-elements/spell-correct.ts
@@ -50,7 +50,7 @@ export class SpellCorrectElement extends InputElement implements PositionedUIEle
     };
   }
 
-  getComponentFactory(): Type<ElementComponent> {
+  getElementComponent(): Type<ElementComponent> {
     return SpellCorrectComponent;
   }
 }
diff --git a/projects/common/models/elements/input-elements/text-area.ts b/projects/common/models/elements/input-elements/text-area.ts
index 434f578a3338d3a68a6a10987325d2b29e206cbd..9c9ba32e000e515af25b5f9cfe267b94b46df004 100644
--- a/projects/common/models/elements/input-elements/text-area.ts
+++ b/projects/common/models/elements/input-elements/text-area.ts
@@ -62,7 +62,7 @@ export class TextAreaElement extends InputElement implements PositionedUIElement
     };
   }
 
-  getComponentFactory(): Type<ElementComponent> {
+  getElementComponent(): Type<ElementComponent> {
     return TextAreaComponent;
   }
 }
diff --git a/projects/common/models/elements/input-elements/text-field.ts b/projects/common/models/elements/input-elements/text-field.ts
index 55cbbf353e4d59cf866f4718c13021a5b4227484..3ced6845e32f98207b3a427f813275ea3bcc4805 100644
--- a/projects/common/models/elements/input-elements/text-field.ts
+++ b/projects/common/models/elements/input-elements/text-field.ts
@@ -9,11 +9,11 @@ import { TextFieldComponent } from 'common/components/input-elements/text-field.
 
 export class TextFieldElement extends InputElement implements PositionedUIElement {
   appearance: 'fill' | 'outline' = 'outline';
-  minLength: number | undefined;
+  minLength: number | null = null;
   minLengthWarnMessage: string = 'Eingabe zu kurz';
-  maxLength: number | undefined;
+  maxLength: number | null = null;
   maxLengthWarnMessage: string = 'Eingabe zu lang';
-  pattern: string | undefined;
+  pattern: string | null = null;
   patternWarnMessage: string = 'Eingabe entspricht nicht der Vorgabe';
   inputAssistancePreset: InputAssistancePreset = null;
   inputAssistancePosition: 'floating' | 'right' = 'floating';
@@ -29,11 +29,11 @@ export class TextFieldElement extends InputElement implements PositionedUIElemen
   constructor(element: Partial<TextFieldElement>, ...args: unknown[]) {
     super({ width: 180, height: 120, ...element }, ...args);
     if (element.appearance) this.appearance = element.appearance;
-    if (element.minLength) this.minLength = element.minLength;
+    if (element.minLength !== undefined) this.minLength = element.minLength;
     if (element.minLengthWarnMessage) this.minLengthWarnMessage = element.minLengthWarnMessage;
-    if (element.maxLength) this.maxLength = element.maxLength;
+    if (element.maxLength !== undefined) this.maxLength = element.maxLength;
     if (element.maxLengthWarnMessage) this.maxLengthWarnMessage = element.maxLengthWarnMessage;
-    if (element.pattern) this.pattern = element.pattern;
+    if (element.pattern !== undefined) this.pattern = element.pattern;
     if (element.patternWarnMessage) this.patternWarnMessage = element.patternWarnMessage;
     if (element.inputAssistancePreset) this.inputAssistancePreset = element.inputAssistancePreset;
     if (element.inputAssistancePosition) this.inputAssistancePosition = element.inputAssistancePosition;
@@ -69,7 +69,7 @@ export class TextFieldElement extends InputElement implements PositionedUIElemen
     };
   }
 
-  getComponentFactory(): Type<ElementComponent> {
+  getElementComponent(): Type<ElementComponent> {
     return TextFieldComponent;
   }
 }
diff --git a/projects/common/models/elements/media-elements/audio.ts b/projects/common/models/elements/media-elements/audio.ts
index 388ac28b0c37f72d709b77e63f04cd14fb9e284b..1bce01b88e5fe095e0eb8cd22a47b35d15b1ea03 100644
--- a/projects/common/models/elements/media-elements/audio.ts
+++ b/projects/common/models/elements/media-elements/audio.ts
@@ -14,7 +14,7 @@ export class AudioElement extends PlayerElement implements PositionedUIElement {
     this.position = ElementFactory.initPositionProps(element.position);
   }
 
-  getComponentFactory(): Type<ElementComponent> {
+  getElementComponent(): Type<ElementComponent> {
     return AudioComponent;
   }
 }
diff --git a/projects/common/models/elements/media-elements/image.ts b/projects/common/models/elements/media-elements/image.ts
index 3c72fd0cc7704774614147e6514fcee9000c0570..38b2e1354a44825cc5ccaffbebb8d76b5dcb3191 100644
--- a/projects/common/models/elements/media-elements/image.ts
+++ b/projects/common/models/elements/media-elements/image.ts
@@ -24,7 +24,7 @@ export class ImageElement extends UIElement implements PositionedUIElement {
     this.position = ElementFactory.initPositionProps(element.position);
   }
 
-  getComponentFactory(): Type<ElementComponent> {
+  getElementComponent(): Type<ElementComponent> {
     return ImageComponent;
   }
 
diff --git a/projects/common/models/elements/media-elements/video.ts b/projects/common/models/elements/media-elements/video.ts
index 89ff862e1664ea3f8bf9793b51aafbfd3eaad7d8..b3e74720711cee7cb4b2204a9b467dd56d52e96c 100644
--- a/projects/common/models/elements/media-elements/video.ts
+++ b/projects/common/models/elements/media-elements/video.ts
@@ -16,7 +16,7 @@ export class VideoElement extends PlayerElement implements PositionedUIElement {
     this.position = ElementFactory.initPositionProps(element.position);
   }
 
-  getComponentFactory(): Type<ElementComponent> {
+  getElementComponent(): Type<ElementComponent> {
     return VideoComponent;
   }
 }
diff --git a/projects/common/models/elements/text/text.ts b/projects/common/models/elements/text/text.ts
index 7b122d20e4ec1e0cbe581f568bbca9a6b89fda1b..277b566de7eb3c7d1105c46f8520c7e7e631bd62 100644
--- a/projects/common/models/elements/text/text.ts
+++ b/projects/common/models/elements/text/text.ts
@@ -57,7 +57,7 @@ export class TextElement extends UIElement implements PositionedUIElement {
     };
   }
 
-  getComponentFactory(): Type<ElementComponent> {
+  getElementComponent(): Type<ElementComponent> {
     return TextComponent;
   }
 }
diff --git a/projects/common/models/section.ts b/projects/common/models/section.ts
index 7a02910058ca32ff172427d16c4d0464776c6e93..3eae3dba822670a52b7929c6117e9ad6389f2522 100644
--- a/projects/common/models/section.ts
+++ b/projects/common/models/section.ts
@@ -1,11 +1,7 @@
 import { Type } from '@angular/core';
 import { IDManager } from 'common/util/id-manager';
 import {
-  InputElement, PlayerElement,
-  PositionedUIElement,
-  AnswerScheme,
-  UIElement,
-  UIElementValue
+  CompoundElement, PositionedUIElement, UIElement, UIElementValue, AnswerScheme
 } from 'common/models/elements/element';
 import { ButtonElement } from 'common/models/elements/button/button';
 import { TextElement } from 'common/models/elements/text/text';
@@ -45,25 +41,25 @@ export class Section {
   activeAfterID: string | null = null;
 
   static ELEMENT_CLASSES: Record<string, Type<UIElement>> = {
-    'text': TextElement,
-    'button': ButtonElement,
+    text: TextElement,
+    button: ButtonElement,
     'text-field': TextFieldElement,
     'text-field-simple': TextFieldSimpleElement,
     'text-area': TextAreaElement,
-    'checkbox': CheckboxElement,
-    'dropdown': DropdownElement,
-    'radio': RadioButtonGroupElement,
-    'image': ImageElement,
-    'audio': AudioElement,
-    'video': VideoElement,
-    'likert': LikertElement,
+    checkbox: CheckboxElement,
+    dropdown: DropdownElement,
+    radio: RadioButtonGroupElement,
+    image: ImageElement,
+    audio: AudioElement,
+    video: VideoElement,
+    likert: LikertElement,
     'radio-group-images': RadioButtonGroupComplexElement,
     'drop-list': DropListElement,
     'drop-list-simple': DropListSimpleElement,
-    'cloze': ClozeElement,
-    'slider': SliderElement,
+    cloze: ClozeElement,
+    slider: SliderElement,
     'spell-correct': SpellCorrectElement,
-    'frame': FrameElement,
+    frame: FrameElement,
     'toggle-button': ToggleButtonElement
   };
 
@@ -90,13 +86,14 @@ export class Section {
   }
 
   addElement(element: PositionedUIElement): void {
+    element.position.dynamicPositioning = this.dynamicPositioning;
     this.elements.push(element);
   }
 
   /* Includes children of children, i.e. compound children. */
   getAllElements(elementType?: string): UIElement[] {
     let allElements: UIElement[] =
-      this.elements.map(element => [element, ...element.getChildElements()])
+      this.elements.map(element => [element, ...(element as CompoundElement).getChildElements() || []])
         .flat();
     if (elementType) {
       allElements = allElements.filter(element => element.type === elementType);
diff --git a/projects/common/pipes/safe-resource-html.pipe.ts b/projects/common/pipes/safe-resource-html.pipe.ts
index f7e63e0fbf8ab81520599c7f84d415feb7cc0de8..e22d8597b8cd28f65b1e16f642416d5de6146d22 100644
--- a/projects/common/pipes/safe-resource-html.pipe.ts
+++ b/projects/common/pipes/safe-resource-html.pipe.ts
@@ -1,5 +1,5 @@
 import { Pipe, PipeTransform } from '@angular/core';
-import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
+import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
 
 @Pipe({
   name: 'safeResourceHTML'
@@ -7,7 +7,7 @@ import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
 export class SafeResourceHTMLPipe implements PipeTransform {
   constructor(private sanitizer: DomSanitizer) {}
 
-  transform(resourceUrl: string): SafeResourceUrl {
-    return this.sanitizer.bypassSecurityTrustHtml(resourceUrl);
+  transform(safeHtml: string): SafeHtml {
+    return this.sanitizer.bypassSecurityTrustHtml(safeHtml);
   }
 }
diff --git a/projects/common/services/id.service.spec.ts b/projects/common/services/id.service.spec.ts
deleted file mode 100644
index efa25193236da5c700a42cf861206e3501e24cc1..0000000000000000000000000000000000000000
--- a/projects/common/services/id.service.spec.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-import { IDManager } from 'common/util/id-manager';
-
-describe('IDService', () => {
-  let service: IDManager;
-
-  beforeEach(() => {
-    service = IDManager.getInstance();
-    service.reset();
-  });
-
-  it('getNewID should fail on empty string param', () => {
-    expect(() => { service.getNewID(''); }).toThrow(Error('ID-Service: No type given!'));
-  });
-
-  it('getNewID should return first ID', () => {
-    expect(service.getNewID('text')).toBe('text_1');
-  });
-
-  it('getNewID should return different IDs - counting up', () => {
-    service.getNewID('text');
-    expect(service.getNewID('text')).toBe('text_2');
-  });
-
-  it('service should return next id when one is already taken', () => {
-    service.addID('text_1');
-    expect(service.getNewID('text')).toBe('text_2');
-  });
-
-  it('isIdAvailable should return false when id is already taken', () => {
-    expect(service.isIdAvailable('text_1')).toBe(true);
-    service.addID('text_1');
-    expect(service.isIdAvailable('text_1')).toBe(false);
-    expect(service.isIdAvailable('text_2')).toBe(true);
-  });
-
-  it('isIdAvailable should return true when ID is returned (freed up)', () => {
-    expect(service.isIdAvailable('text_1')).toBe(true);
-    service.addID('text_1');
-    expect(service.isIdAvailable('text_1')).toBe(false);
-    service.removeId('text_1');
-    expect(service.isIdAvailable('text_1')).toBe(true);
-  });
-});
diff --git a/projects/common/services/sanitization.service.ts b/projects/common/services/sanitization.service.ts
index bf57a0c950602eedee9021dc8a17ef396a98d676..0da73c37bb67d241c56cd5b213d33da613d5f28d 100644
--- a/projects/common/services/sanitization.service.ts
+++ b/projects/common/services/sanitization.service.ts
@@ -1,7 +1,5 @@
 import { Injectable } from '@angular/core';
-import packageJSON from '../../../package.json';
 import { Editor } from '@tiptap/core';
-import StarterKit from '@tiptap/starter-kit';
 import ToggleButtonExtension from
   'common/models/elements/compound-elements/cloze/tiptap-editor-extensions/toggle-button';
 import DropListExtension from 'common/models/elements/compound-elements/cloze/tiptap-editor-extensions/drop-list';
@@ -10,7 +8,7 @@ import { Unit } from 'common/models/unit';
 import {
   BasicStyles, DragNDropValueObject, ExtendedStyles,
   InputElement, PlayerProperties,
-  PositionedUIElement, PositionProperties, TextImageLabel,
+  PositionedUIElement, PositionProperties, TextImageLabel, TextLabel,
   UIElement, UIElementValue
 } from 'common/models/elements/element';
 import { LikertElement } from 'common/models/elements/compound-elements/likert/likert';
@@ -28,12 +26,13 @@ import { DropListElement } from 'common/models/elements/input-elements/drop-list
 import { Page } from 'common/models/page';
 import { Section } from 'common/models/section';
 import { IDManager } from 'common/util/id-manager';
+import packageJSON from '../../../package.json';
+import { RadioButtonGroupComplexElement } from 'common/models/elements/input-elements/radio-button-group-complex';
 
 @Injectable({
   providedIn: 'root'
 })
 export class SanitizationService {
-
   private static expectedUnitVersion: [number, number, number] =
     packageJSON.config.unit_definition_version.split('.') as unknown as [number, number, number];
 
@@ -118,8 +117,8 @@ export class SanitizationService {
       .includes(newElement.type as string)) {
       newElement = SanitizationService.handlePlusOne(newElement as InputElement);
     }
-    if (['radio'].includes(newElement.type as string)) {
-      newElement = SanitizationService.handleRadioButtonGroupElement(newElement as RadioButtonGroupElement);
+    if (['radio-group-images'].includes(newElement.type as string)) {
+      newElement = SanitizationService.fixImageLabel(newElement as RadioButtonGroupComplexElement);
     }
     if (['likert'].includes(newElement.type as string)) {
       newElement = this.handleLikertElement(newElement as LikertElement);
@@ -308,7 +307,7 @@ export class SanitizationService {
     });
 
     const editor = new Editor({
-      extensions: [StarterKit, ToggleButtonExtension, DropListExtension, TextFieldExtension],
+      extensions: [ToggleButtonExtension, DropListExtension, TextFieldExtension],
       content: replacedText
     });
     return editor.getJSON() as ClozeDocument;
@@ -324,7 +323,9 @@ export class SanitizationService {
       (newElement.options as string[]).forEach(option => {
         (newElement.value as DragNDropValueObject[]).push({
           id: IDManager.getInstance().getNewID('value'),
-          stringValue: option
+          text: option,
+          imgSrc: null,
+          imgPosition: 'above'
         });
       });
     }
@@ -333,9 +334,18 @@ export class SanitizationService {
       (newElement.value as string[]).forEach(value => {
         newValues.push({
           id: IDManager.getInstance().getNewID('value'),
-          stringValue: value
+          text: value,
+          imgSrc: null,
+          imgPosition: 'above'
         });
       });
+      // fix DragNDropValueObject stringValue -> text
+      //  imgSrcValue -> imgSrc
+      (newElement as DropListElement).value.forEach((valueObject: any) => {
+        valueObject.text = valueObject.text || valueObject.stringValue;
+        valueObject.imgSrc = valueObject.text || valueObject.imgSrcValue;
+        valueObject.imgPosition = valueObject.imgPosition || valueObject.position;
+      });
       newElement.value = newValues;
     }
     return newElement as DropListElement;
@@ -344,21 +354,19 @@ export class SanitizationService {
   private handleLikertElement(element: LikertElement): LikertElement {
     return new LikertElement({
       ...element,
+      options: element.options || element.columns,
       rows: element.rows
         .map((row: LikertRowElement) => this.sanitizeElement(row as Record<string, UIElementValue>) as LikertRowElement)
     });
   }
 
   private static handleLikertRowElement(element: Record<string, UIElementValue>): Partial<LikertRowElement> {
-    if (element.rowLabel) {
-      return element;
-    }
     return new LikertRowElement({
       ...element,
       rowLabel: {
         text: element.text,
-        imgSrc: null,
-        position: 'above'
+        imgSrc: element.imgSrc,
+        imgPosition: element.imgPosition || element.position || 'above'
       } as TextImageLabel
     });
   }
@@ -373,23 +381,20 @@ export class SanitizationService {
       element;
   }
 
-  private static handleRadioButtonGroupElement(element: RadioButtonGroupElement): RadioButtonGroupElement {
+  private static handleToggleButtonElement(element: ToggleButtonElement): ToggleButtonElement {
     if (element.richTextOptions) {
       return element;
     }
-    return new RadioButtonGroupElement({
+    return new ToggleButtonElement({
       ...element,
       richTextOptions: element.options as string[]
     });
   }
 
-  private static handleToggleButtonElement(element: ToggleButtonElement): ToggleButtonElement {
-    if (element.richTextOptions) {
-      return element;
-    }
-    return new ToggleButtonElement({
-      ...element,
-      richTextOptions: element.options as string[]
+  private static fixImageLabel(element: RadioButtonGroupComplexElement) {
+    element.options.forEach(option => {
+      option.imgPosition = option.imgPosition || (option as any).position || 'above';
     });
+    return element;
   }
 }
diff --git a/projects/common/util/element.factory.ts b/projects/common/util/element.factory.ts
index 7573c6f82d674b400bea45fdb2b718171d48b3ef..f0a15675a39b1a82a7d744da472f7be69a95a536 100644
--- a/projects/common/util/element.factory.ts
+++ b/projects/common/util/element.factory.ts
@@ -35,14 +35,6 @@ export abstract class ElementFactory {
     };
   }
 
-  static initTextImageLabel(): TextImageLabel {
-    return {
-      text: '',
-      imgSrc: null,
-      position: 'above'
-    };
-  }
-
   static initPlayerProps(defaults: Partial<PlayerProperties> = {}): PlayerProperties {
     return {
       autostart: defaults.autostart !== undefined ? defaults.autostart as boolean : false,
@@ -71,4 +63,12 @@ export abstract class ElementFactory {
       playbackTime: defaults.playbackTime !== undefined ? defaults.playbackTime as number : 0
     };
   }
+
+  static createOptionLabel(optionText: string, addImg: boolean = false) {
+    return {
+      text: optionText,
+      imgSrc: addImg ? null : undefined,
+      imgPosition: addImg ? 'above' : undefined
+    };
+  }
 }
diff --git a/projects/common/util/id-manager.spec.ts b/projects/common/util/id-manager.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..9ecc529763e77fba4475f498e7349276c290bf4e
--- /dev/null
+++ b/projects/common/util/id-manager.spec.ts
@@ -0,0 +1,43 @@
+import { IDManager } from 'common/util/id-manager';
+
+describe('IDService', () => {
+  let manager: IDManager;
+
+  beforeEach(() => {
+    manager = IDManager.getInstance();
+    manager.reset();
+  });
+
+  it('getNewID should fail on empty string param', () => {
+    expect(() => { manager.getNewID(''); }).toThrow(Error('ID-Service: No type given!'));
+  });
+
+  it('getNewID should return first ID', () => {
+    expect(manager.getNewID('text')).toBe('text_1');
+  });
+
+  it('getNewID should return different IDs - counting up', () => {
+    manager.getNewID('text');
+    expect(manager.getNewID('text')).toBe('text_2');
+  });
+
+  it('manager should return next id when one is already taken', () => {
+    manager.addID('text_1');
+    expect(manager.getNewID('text')).toBe('text_2');
+  });
+
+  it('isIdAvailable should return false when id is already taken', () => {
+    expect(manager.isIdAvailable('text_1')).toBe(true);
+    manager.addID('text_1');
+    expect(manager.isIdAvailable('text_1')).toBe(false);
+    expect(manager.isIdAvailable('text_2')).toBe(true);
+  });
+
+  it('isIdAvailable should return true when ID is returned (freed up)', () => {
+    expect(manager.isIdAvailable('text_1')).toBe(true);
+    manager.addID('text_1');
+    expect(manager.isIdAvailable('text_1')).toBe(false);
+    manager.removeId('text_1');
+    expect(manager.isIdAvailable('text_1')).toBe(true);
+  });
+});
diff --git a/projects/common/util/id-manager.ts b/projects/common/util/id-manager.ts
index 09bc3eb92a4458c4a671b5d1d9601ab585a36745..71c523239dfce0c81cb971e87db923e4a0356d85 100644
--- a/projects/common/util/id-manager.ts
+++ b/projects/common/util/id-manager.ts
@@ -28,8 +28,11 @@ export class IDManager {
     value: 0
   };
 
-  static getInstance() {
-    return this.instance || (this.instance = new this());
+  static getInstance(): IDManager {
+    if (!this.instance) {
+      this.instance = new this();
+    }
+    return this.instance;
   }
 
   getNewID(type: string): string {
diff --git a/projects/editor/src/app/app.component.ts b/projects/editor/src/app/app.component.ts
index 518cfb9ee1ad4a0cb50f08f67ab9a07dcde40212..09a99e46fa02d5fec443e64208374ba84fbf8423 100644
--- a/projects/editor/src/app/app.component.ts
+++ b/projects/editor/src/app/app.component.ts
@@ -9,7 +9,7 @@ import { UnitService } from './services/unit.service';
   selector: 'aspect-editor',
   template: `
     <div fxLayout="column" class="mainView">
-      <aspect-toolbar *ngIf="isStandalone()"></aspect-toolbar>
+      <aspect-toolbar *ngIf="isStandalone"></aspect-toolbar>
       <aspect-unit-view fxFlex></aspect-unit-view>
     </div>
   `,
@@ -18,7 +18,7 @@ import { UnitService } from './services/unit.service';
   ]
 })
 export class AppComponent implements OnInit {
-  isStandalone = (): boolean => window === window.parent;
+  isStandalone = window === window.parent;
 
   constructor(private unitService: UnitService,
               private translateService: TranslateService,
diff --git a/projects/editor/src/app/app.module.ts b/projects/editor/src/app/app.module.ts
index 605bbb69eaa6b5a75852a5986f79959678306e6e..8a53bd3fa9b27cef8e154992b5e39ca1b497c3d3 100644
--- a/projects/editor/src/app/app.module.ts
+++ b/projects/editor/src/app/app.module.ts
@@ -19,17 +19,18 @@ import { MatDividerModule } from '@angular/material/divider';
 import { MatInputModule } from '@angular/material/input';
 import { MatListModule } from '@angular/material/list';
 
+import { SharedModule } from 'common/shared.module';
+import { SectionInsertDialogComponent } from 'editor/src/app/components/dialogs/section-insert-dialog.component';
 import { AppComponent } from './app.component';
 import { ToolbarComponent } from './components/toolbar/toolbar.component';
 import { UiElementToolboxComponent } from
-    './components/new-ui-element-panel/ui-element-toolbox.component';
+  './components/new-ui-element-panel/ui-element-toolbox.component';
 import { UnitViewComponent } from './components/unit-view/unit-view.component';
 import { CanvasComponent } from './components/canvas/canvas.component';
 import { StaticCanvasOverlayComponent } from
-    './components/canvas/overlays/static-canvas-overlay.component';
+  './components/canvas/overlays/static-canvas-overlay.component';
 import { DynamicCanvasOverlayComponent } from
-    './components/canvas/overlays/dynamic-canvas-overlay.component';
-import { SharedModule } from 'common/shared.module';
+  './components/canvas/overlays/dynamic-canvas-overlay.component';
 import { EditorTranslateLoader } from './editor-translate-loader';
 import { SectionMenuComponent } from './components/canvas/section-menu.component';
 import { SectionStaticComponent } from './components/canvas/section-static.component';
@@ -39,7 +40,6 @@ import { ConfirmationDialogComponent } from './components/dialogs/confirmation-d
 import { TextEditDialogComponent } from './components/dialogs/text-edit-dialog.component';
 import { TextEditMultilineDialogComponent } from './components/dialogs/text-edit-multiline-dialog.component';
 import { PlayerEditDialogComponent } from './components/dialogs/player-edit-dialog.component';
-import { ColumnHeaderEditDialogComponent } from './components/dialogs/column-header-edit-dialog.component';
 import { LikertRowEditDialogComponent } from './components/dialogs/likert-row-edit-dialog.component';
 import { RichTextEditDialogComponent } from './components/dialogs/rich-text-edit-dialog.component';
 import { DropListOptionEditDialogComponent } from './components/dialogs/drop-list-option-edit-dialog.component';
@@ -48,29 +48,45 @@ import { ToggleButtonNodeviewComponent } from './text-editor/angular-node-views/
 import { TextFieldNodeviewComponent } from './text-editor/angular-node-views/text-field-nodeview.component';
 import { DropListNodeviewComponent } from './text-editor/angular-node-views/drop-list-nodeview.component';
 import { PositionFieldSetComponent } from
-    './components/properties-panel/position-properties-tab/input-groups/position-field-set.component';
+  './components/properties-panel/position-properties-tab/input-groups/position-field-set.component';
 import { DimensionFieldSetComponent } from
-    './components/properties-panel/position-properties-tab/input-groups/dimension-field-set.component';
+  './components/properties-panel/position-properties-tab/input-groups/dimension-field-set.component';
 import { ElementPropertiesPanelComponent }
   from './components/properties-panel/element-properties-panel.component';
 import { ElementPositionPropertiesComponent } from
-    './components/properties-panel/position-properties-tab/element-position-properties.component';
+  './components/properties-panel/position-properties-tab/element-position-properties.component';
 import { ElementStylePropertiesComponent } from
-    './components/properties-panel/style-properties-tab/element-style-properties.component';
+  './components/properties-panel/style-properties-tab/element-style-properties.component';
 import { ElementModelPropertiesComponent } from
-    './components/properties-panel/model-properties-tab/element-model-properties.component';
+  './components/properties-panel/model-properties-tab/element-model-properties.component';
 import { DynamicSectionHelperGridComponent } from './components/canvas/dynamic-section-helper-grid.component';
 import { ElementGridChangeListenerDirective } from './components/canvas/element-grid-change-listener.directive';
-import { OptionsFieldSetComponent } from './components/properties-panel/model-properties-tab/input-groups/options-field-set.component';
-import { TextPropertiesFieldSetComponent } from './components/properties-panel/model-properties-tab/input-groups/text-properties-field-set.component';
-import { ButtonPropertiesComponent } from './components/properties-panel/model-properties-tab/input-groups/button-properties.component';
-import { SliderPropertiesComponent } from './components/properties-panel/model-properties-tab/input-groups/slider-properties.component';
-import { InputElementPropertiesComponent } from './components/properties-panel/model-properties-tab/input-groups/input-element-properties.component';
-import { ImagePropertiesComponent } from './components/properties-panel/model-properties-tab/input-groups/image-properties.component';
-import { DropListPropertiesComponent } from './components/properties-panel/model-properties-tab/input-groups/drop-list-properties.component';
+import { OptionsFieldSetComponent } from
+  './components/properties-panel/model-properties-tab/input-groups/options-field-set.component';
+import { TextPropertiesFieldSetComponent } from
+  './components/properties-panel/model-properties-tab/input-groups/text-properties-field-set.component';
+import { ButtonPropertiesComponent } from
+  './components/properties-panel/model-properties-tab/input-groups/button-properties.component';
+import { SliderPropertiesComponent } from
+  './components/properties-panel/model-properties-tab/input-groups/slider-properties.component';
+import { TextFieldElementPropertiesComponent } from
+  './components/properties-panel/model-properties-tab/input-groups/text-field-element-properties.component';
+import { ScaleAndZoomPropertiesComponent } from
+  './components/properties-panel/model-properties-tab/input-groups/scale-and-zoom-properties.component';
+import { DropListPropertiesComponent } from
+  './components/properties-panel/model-properties-tab/input-groups/drop-list-properties.component';
 import { RichTextEditorSimpleComponent } from './text-editor-simple/rich-text-editor-simple.component';
 import { RichTextSimpleEditDialogComponent } from './components/dialogs/rich-text-simple-edit-dialog.component';
-import { SectionInsertDialogComponent } from 'editor/src/app/components/dialogs/section-insert-dialog.component';
+import { SelectPropertiesComponent } from
+  './components/properties-panel/model-properties-tab/input-groups/select-properties.component';
+import { InputElementPropertiesComponent } from
+  './components/properties-panel/model-properties-tab/input-groups/input-element-properties.component';
+import { PresetValuePropertiesComponent } from
+  './components/properties-panel/model-properties-tab/input-groups/preset-value-properties.component';
+import { OptionListPanelComponent } from './components/properties-panel/option-list-panel.component';
+import { LikertRowLabelPipe } from './components/properties-panel/likert-row-label.pipe';
+import { LabelEditDialogComponent } from './components/dialogs/label-edit-dialog.component';
+import { BorderPropertiesComponent } from './components/properties-panel/model-properties-tab/input-groups/border-properties.component';
 
 @NgModule({
   declarations: [
@@ -95,7 +111,6 @@ import { SectionInsertDialogComponent } from 'editor/src/app/components/dialogs/
     TextEditDialogComponent,
     TextEditMultilineDialogComponent,
     PlayerEditDialogComponent,
-    ColumnHeaderEditDialogComponent,
     LikertRowEditDialogComponent,
     RichTextEditDialogComponent,
     ElementModelPropertiesComponent,
@@ -108,12 +123,19 @@ import { SectionInsertDialogComponent } from 'editor/src/app/components/dialogs/
     TextPropertiesFieldSetComponent,
     ButtonPropertiesComponent,
     SliderPropertiesComponent,
-    InputElementPropertiesComponent,
-    ImagePropertiesComponent,
+    TextFieldElementPropertiesComponent,
+    ScaleAndZoomPropertiesComponent,
     DropListPropertiesComponent,
     RichTextEditorSimpleComponent,
     RichTextSimpleEditDialogComponent,
-    SectionInsertDialogComponent
+    SectionInsertDialogComponent,
+    SelectPropertiesComponent,
+    InputElementPropertiesComponent,
+    PresetValuePropertiesComponent,
+    OptionListPanelComponent,
+    LikertRowLabelPipe,
+    LabelEditDialogComponent,
+    BorderPropertiesComponent
   ],
   imports: [
     BrowserModule,
diff --git a/projects/editor/src/app/components/canvas/canvas.component.ts b/projects/editor/src/app/components/canvas/canvas.component.ts
index 4fc948d6be6d257dbd081aa5b354b9941f5442b1..ff640c329afa5b5068e0d9c279038fe0d7fcef39 100644
--- a/projects/editor/src/app/components/canvas/canvas.component.ts
+++ b/projects/editor/src/app/components/canvas/canvas.component.ts
@@ -2,14 +2,14 @@ import {
   Component, Input, QueryList, ViewChildren
 } from '@angular/core';
 import { CdkDragDrop } from '@angular/cdk/drag-drop';
+import { PositionedUIElement, UIElement } from 'common/models/elements/element';
+import { Page } from 'common/models/page';
+import { Section } from 'common/models/section';
 import { UnitService } from '../../services/unit.service';
 import { SelectionService } from '../../services/selection.service';
 import { CanvasElementOverlay } from './overlays/canvas-element-overlay';
 import { SectionStaticComponent } from './section-static.component';
 import { SectionDynamicComponent } from './section-dynamic.component';
-import { PositionedUIElement, UIElement } from 'common/models/elements/element';
-import { Page } from 'common/models/page';
-import { Section } from 'common/models/section';
 
 @Component({
   selector: 'aspect-page-canvas',
diff --git a/projects/editor/src/app/components/canvas/dynamic-section-helper-grid.component.ts b/projects/editor/src/app/components/canvas/dynamic-section-helper-grid.component.ts
index f8c898252a7e5a65c19df8988a3519727aba2084..756b579929865842311ca037b2ba0289bc3cc181 100644
--- a/projects/editor/src/app/components/canvas/dynamic-section-helper-grid.component.ts
+++ b/projects/editor/src/app/components/canvas/dynamic-section-helper-grid.component.ts
@@ -2,9 +2,9 @@ import { CdkDragDrop } from '@angular/cdk/drag-drop/drag-events';
 import {
   Component, ElementRef, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges
 } from '@angular/core';
-import { UnitService } from '../../services/unit.service';
 import { UIElement, UIElementType } from 'common/models/elements/element';
 import { Section } from 'common/models/section';
+import { UnitService } from '../../services/unit.service';
 
 @Component({
   selector: '[app-dynamic-section-helper-grid]',
@@ -44,7 +44,7 @@ export class DynamicSectionHelperGridComponent implements OnInit, OnChanges {
   columnCountArray: unknown[] = [];
   rowCountArray: unknown[] = [];
 
-  constructor(public unitService: UnitService, public ele: ElementRef) {}
+  constructor(public unitService: UnitService) {}
 
   ngOnInit(): void {
     this.calculateColumnCount();
diff --git a/projects/editor/src/app/components/canvas/overlays/canvas-element-overlay.ts b/projects/editor/src/app/components/canvas/overlays/canvas-element-overlay.ts
index 1388d7d083fd83c859ec15bce599e5434caac81e..a48bce6829376430281a886a844c94d54c9f244c 100644
--- a/projects/editor/src/app/components/canvas/overlays/canvas-element-overlay.ts
+++ b/projects/editor/src/app/components/canvas/overlays/canvas-element-overlay.ts
@@ -4,14 +4,14 @@ import {
 } from '@angular/core';
 import { Subject } from 'rxjs';
 import { takeUntil } from 'rxjs/operators';
-import { UnitService } from '../../../services/unit.service';
 import { ElementComponent } from 'common/directives/element-component.directive';
-import { SelectionService } from '../../../services/selection.service';
 import { CompoundElementComponent } from 'common/directives/compound-element.directive';
 import { ClozeComponent } from 'common/components/compound-elements/cloze/cloze.component';
 import { CompoundChildOverlayComponent } from
   'common/components/compound-elements/cloze/compound-child-overlay.component';
 import { UIElement } from 'common/models/elements/element';
+import { UnitService } from '../../../services/unit.service';
+import { SelectionService } from '../../../services/selection.service';
 
 @Directive()
 export abstract class CanvasElementOverlay implements OnInit, OnDestroy {
@@ -30,7 +30,7 @@ export abstract class CanvasElementOverlay implements OnInit, OnDestroy {
               private changeDetectorRef: ChangeDetectorRef) { }
 
   ngOnInit(): void {
-    this.childComponent = this.elementContainer.createComponent(this.element.getComponentFactory());
+    this.childComponent = this.elementContainer.createComponent(this.element.getElementComponent());
     this.childComponent.instance.elementModel = this.element;
 
     // Make children not clickable. This way the only relevant events are managed by the overlay.
@@ -62,19 +62,16 @@ export abstract class CanvasElementOverlay implements OnInit, OnDestroy {
     this.changeDetectorRef.detectChanges();
   }
 
-  selectElement(multiSelect: boolean = false): void {
-    if (multiSelect) {
-      this.selectionService.selectElement({ elementComponent: this, multiSelect: true });
-    } else {
-      this.selectionService.selectElement({ elementComponent: this, multiSelect: false });
-    }
-  }
-
-  elementClicked(event: MouseEvent): void { //TODO method name
+  selectElement(event?: MouseEvent): void {
     if (!this.isSelected) {
-      this.selectElement(event.shiftKey);
+      // this.selectElement(event.shiftKey);
+      if (event?.shiftKey) {
+        this.selectionService.selectElement({ elementComponent: this, multiSelect: true });
+      } else {
+        this.selectionService.selectElement({ elementComponent: this, multiSelect: false });
+      }
     }
-    event.stopPropagation();
+    event?.stopPropagation();
     this.elementSelected.emit();
   }
 
diff --git a/projects/editor/src/app/components/canvas/overlays/dynamic-canvas-overlay.component.ts b/projects/editor/src/app/components/canvas/overlays/dynamic-canvas-overlay.component.ts
index 463674409aae453bbea99dda06d134b1b1e03b5f..c0a9cb8d2969be02f15a7d6410c7a01226e67692 100644
--- a/projects/editor/src/app/components/canvas/overlays/dynamic-canvas-overlay.component.ts
+++ b/projects/editor/src/app/components/canvas/overlays/dynamic-canvas-overlay.component.ts
@@ -6,29 +6,29 @@ import { CanvasElementOverlay } from './canvas-element-overlay';
 @Component({
   selector: 'aspect-dynamic-canvas-overlay',
   template: `
-      <!-- TabIndex is needed to make the div selectable and catch keyboard events (delete). -->
-      <!-- DragStart and DragEnd are part of a cursor hack to style the body. See global styling file. -->
-      <div #draggableElement class="draggable-element"
-           [class.fixed-size-content-wrapper]="element.position?.dynamicPositioning &&
+    <!-- TabIndex is needed to make the div selectable and catch keyboard events (delete). -->
+    <!-- DragStart and DragEnd are part of a cursor hack to style the body. See global styling file. -->
+    <div #draggableElement class="draggable-element"
+         [class.fixed-size-content-wrapper]="element.position?.dynamicPositioning &&
                                                element.position?.fixedSize"
-           [class.temporaryHighlight]="temporaryHighlight"
-           tabindex="-1"
-           cdkDrag [cdkDragData]="{dragType: 'move', element: element}"
-           (click)="elementClicked($event)" (dblclick)="openEditDialog()"
-           (cdkDragStarted)="moveDragStart()"
-           (cdkDragEnded)="moveDragEnd()"
-           [style.outline]="isSelected ? 'purple solid 1px' : ''"
-           [style.z-index]="isSelected ? 2 : 1">
-          <div *cdkDragPlaceholder></div>
-          <div [class.fixed-size-content]="element.position?.dynamicPositioning &&
+         [class.temporaryHighlight]="temporaryHighlight"
+         tabindex="-1"
+         cdkDrag [cdkDragData]="{dragType: 'move', element: element}"
+         (click)="selectElement($event)" (dblclick)="openEditDialog()"
+         (cdkDragStarted)="selectElement(); moveDragStart()"
+         (cdkDragEnded)="moveDragEnd()"
+         [style.outline]="isSelected ? 'purple solid 1px' : ''"
+         [style.z-index]="isSelected ? 2 : 1">
+      <div *cdkDragPlaceholder></div>
+      <div [class.fixed-size-content]="element.position?.dynamicPositioning &&
             element.position?.fixedSize"
-               [style.width]="element.position?.dynamicPositioning && element.position?.fixedSize ?
+           [style.width]="element.position?.dynamicPositioning && element.position?.fixedSize ?
                       element.width + 'px' : '100%'"
-               [style.height]="element.position?.dynamicPositioning && element.position?.fixedSize ?
+           [style.height]="element.position?.dynamicPositioning && element.position?.fixedSize ?
                       element.height + 'px' : '100%'">
-              <ng-template #elementContainer></ng-template>
-          </div>
+        <ng-template #elementContainer></ng-template>
       </div>
+    </div>
   `,
   styles: [
     '.draggable-element {width: 100%; height: 100%}',
@@ -42,7 +42,6 @@ export class DynamicCanvasOverlayComponent extends CanvasElementOverlay {
   bodyElement: HTMLElement = document.body;
 
   moveDragStart(): void {
-    this.selectElement();
     this.bodyElement.classList.add('inheritCursors');
     this.bodyElement.style.cursor = 'move';
   }
diff --git a/projects/editor/src/app/components/canvas/overlays/static-canvas-overlay.component.ts b/projects/editor/src/app/components/canvas/overlays/static-canvas-overlay.component.ts
index 1b6ee4fb6475f743f5d9fb892218d5e7aae64aa8..cd2a2f70d965ffa0f9d50650d1ea05921bf893a6 100644
--- a/projects/editor/src/app/components/canvas/overlays/static-canvas-overlay.component.ts
+++ b/projects/editor/src/app/components/canvas/overlays/static-canvas-overlay.component.ts
@@ -1,8 +1,8 @@
 import { Component } from '@angular/core';
 import { take } from 'rxjs/operators';
 import { CdkDragEnd, CdkDragMove } from '@angular/cdk/drag-drop';
-import { CanvasElementOverlay } from './canvas-element-overlay';
 import { UIElement } from 'common/models/elements/element';
+import { CanvasElementOverlay } from './canvas-element-overlay';
 
 @Component({
   selector: 'aspect-static-canvas-overlay',
@@ -11,11 +11,11 @@ import { UIElement } from 'common/models/elements/element';
     <!-- TabIndex is needed to make the div selectable and catch keyboard events (delete). -->
     <div class="draggable-element"
          [class.temporaryHighlight]="temporaryHighlight"
-         (click)="elementClicked($event)"
+         (click)="selectElement($event)"
          (dblclick)="openEditDialog()"
          (keyup.delete)="deleteSelectedElements()" tabindex="-1"
          cdkDrag [cdkDragData]="{dragType: 'move', element: element}"
-         (cdkDragStarted)="!isSelected && selectElement()"
+         (cdkDragStarted)="selectElement()"
          cdkDropList>
       <div *cdkDragPlaceholder></div>
       <!-- Needs extra div because styling can interfere with drag and drop-->
diff --git a/projects/editor/src/app/components/canvas/section-dynamic.component.ts b/projects/editor/src/app/components/canvas/section-dynamic.component.ts
index c0b2ff0015750ed9f5edec94c04fccbb10746a80..93d8af2610d3987831bd0592a7d9c40a90e37438 100644
--- a/projects/editor/src/app/components/canvas/section-dynamic.component.ts
+++ b/projects/editor/src/app/components/canvas/section-dynamic.component.ts
@@ -2,9 +2,9 @@ import {
   Component, Input, Output, EventEmitter,
   ViewChildren, QueryList, ViewChild
 } from '@angular/core';
+import { Section } from 'common/models/section';
 import { CanvasElementOverlay } from './overlays/canvas-element-overlay';
 import { DynamicSectionHelperGridComponent } from './dynamic-section-helper-grid.component';
-import { Section } from 'common/models/section';
 
 @Component({
   selector: 'aspect-section-dynamic',
diff --git a/projects/editor/src/app/components/canvas/section-menu.component.ts b/projects/editor/src/app/components/canvas/section-menu.component.ts
index b3ce0f25425cdfaa65f000d18d65ec4176607c73..6aba70d35d5adce4444370e4ab38c808026d0fcf 100644
--- a/projects/editor/src/app/components/canvas/section-menu.component.ts
+++ b/projects/editor/src/app/components/canvas/section-menu.component.ts
@@ -5,12 +5,12 @@ import {
 import { Subject } from 'rxjs';
 import { takeUntil } from 'rxjs/operators';
 import { Clipboard } from '@angular/cdk/clipboard';
-import { UnitService } from '../../services/unit.service';
-import { DialogService } from '../../services/dialog.service';
-import { SelectionService } from '../../services/selection.service';
 import { MessageService } from 'common/services/message.service';
 import { UIElement } from 'common/models/elements/element';
 import { Section } from 'common/models/section';
+import { UnitService } from '../../services/unit.service';
+import { DialogService } from '../../services/dialog.service';
+import { SelectionService } from '../../services/selection.service';
 
 @Component({
   selector: 'aspect-section-menu',
diff --git a/projects/editor/src/app/components/canvas/section-static.component.ts b/projects/editor/src/app/components/canvas/section-static.component.ts
index 07ff70cd9f928f100896f5f1bc799f7efe27becb..79766c964a138d3ba56dc6fe6b0dca99481780f2 100644
--- a/projects/editor/src/app/components/canvas/section-static.component.ts
+++ b/projects/editor/src/app/components/canvas/section-static.component.ts
@@ -1,10 +1,10 @@
 import {
   Component, ElementRef, EventEmitter, Input, Output, QueryList, ViewChild, ViewChildren
 } from '@angular/core';
-import { UnitService } from '../../services/unit.service';
-import { CanvasElementOverlay } from './overlays/canvas-element-overlay';
 import { Section } from 'common/models/section';
 import { UIElementType } from 'common/models/elements/element';
+import { UnitService } from '../../services/unit.service';
+import { CanvasElementOverlay } from './overlays/canvas-element-overlay';
 
 @Component({
   selector: 'aspect-section-static',
diff --git a/projects/editor/src/app/components/dialogs/column-header-edit-dialog.component.ts b/projects/editor/src/app/components/dialogs/column-header-edit-dialog.component.ts
deleted file mode 100644
index 2458150c02da51771e9d3c1c1e07f0fff2b80fc4..0000000000000000000000000000000000000000
--- a/projects/editor/src/app/components/dialogs/column-header-edit-dialog.component.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-import { Component, Inject } from '@angular/core';
-import { MAT_DIALOG_DATA } from '@angular/material/dialog';
-import { FileService } from 'common/services/file.service';
-import { TextImageLabel } from 'common/models/elements/element';
-
-@Component({
-  selector: 'aspect-likert-column-edit-dialog',
-  template: `
-    <mat-dialog-content fxLayout="column">
-      <aspect-rich-text-editor-simple [content]="data.column.text"
-                                      [defaultFontSize]="data.defaultFontSize"
-                                      (contentChange)="this.textContent = $event">
-      </aspect-rich-text-editor-simple>
-
-      <button mat-raised-button (click)="loadImage()">{{ 'loadImage' | translate }}</button>
-      <button mat-raised-button (click)="imgSrc = null">{{ 'removeImage' | translate }}</button>
-      <img [src]="imgSrc"
-           [style.object-fit]="'scale-down'"
-           [width]="200">
-      <mat-form-field appearance="fill">
-        <mat-label>{{'position' | translate }}</mat-label>
-        <mat-select #positionSelect [value]="data.column.position">
-          <mat-option *ngFor="let option of ['above', 'below']"
-                      [value]="option">
-            {{ option | translate }}
-          </mat-option>
-        </mat-select>
-      </mat-form-field>
-    </mat-dialog-content>
-    <mat-dialog-actions>
-      <button mat-button [mat-dialog-close]="{
-                         text: textContent,
-                         imgSrc: imgSrc,
-                         position: positionSelect.value }">
-        {{'save' | translate }}
-      </button>
-      <button mat-button mat-dialog-close>{{'cancel' | translate }}</button>
-    </mat-dialog-actions>
-  `,
-  styles: [
-    'aspect-rich-text-editor-simple {margin-bottom: 20px;}'
-  ]
-})
-export class ColumnHeaderEditDialogComponent {
-  constructor(@Inject(MAT_DIALOG_DATA) public data: { column: TextImageLabel, defaultFontSize: number }) { }
-  textContent: string = this.data.column.text;
-  imgSrc: string | null = this.data.column.imgSrc;
-
-  async loadImage(): Promise<void> {
-    this.imgSrc = await FileService.loadImage();
-  }
-}
diff --git a/projects/editor/src/app/components/dialogs/drop-list-option-edit-dialog.component.ts b/projects/editor/src/app/components/dialogs/drop-list-option-edit-dialog.component.ts
index 6e06a9c596dfec8a21a556196265219859fe3719..387774c772833190f57333ac013f321def10fcf6 100644
--- a/projects/editor/src/app/components/dialogs/drop-list-option-edit-dialog.component.ts
+++ b/projects/editor/src/app/components/dialogs/drop-list-option-edit-dialog.component.ts
@@ -9,10 +9,10 @@ import { DragNDropValueObject } from 'common/models/elements/element';
     <mat-dialog-content fxLayout="column">
       <mat-form-field>
         <mat-label>{{'text' | translate }}</mat-label>
-        <input #textField matInput type="text" [value]="data.value.stringValue">
+        <input #textField matInput type="text" [value]="data.value.text">
       </mat-form-field>
       <button mat-raised-button (click)="loadImage()">{{ 'loadImage' | translate }}</button>
-      <button mat-raised-button (click)="imgSrc = undefined">{{ 'removeImage' | translate }}</button>
+      <button mat-raised-button (click)="imgSrc = null">{{ 'removeImage' | translate }}</button>
       <img [src]="imgSrc"
            [style.object-fit]="'scale-down'"
            [width]="200">
@@ -23,8 +23,8 @@ import { DragNDropValueObject } from 'common/models/elements/element';
     </mat-dialog-content>
     <mat-dialog-actions>
       <button mat-button [mat-dialog-close]="{
-        stringValue: textField.value,
-        imgSrcValue: imgSrc,
+        text: textField.value,
+        imgSrc: imgSrc,
         id: idField.value
       } ">
         {{'save' | translate }}
@@ -35,7 +35,7 @@ import { DragNDropValueObject } from 'common/models/elements/element';
 })
 export class DropListOptionEditDialogComponent {
   constructor(@Inject(MAT_DIALOG_DATA) public data: { value: DragNDropValueObject }) { }
-  imgSrc: string | undefined = this.data.value.imgSrcValue;
+  imgSrc: string | null = this.data.value.imgSrc;
 
   async loadImage(): Promise<void> {
     this.imgSrc = await FileService.loadImage();
diff --git a/projects/editor/src/app/components/dialogs/label-edit-dialog.component.ts b/projects/editor/src/app/components/dialogs/label-edit-dialog.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7aec0d6e220ba1230c9e9409d556e9244c08831b
--- /dev/null
+++ b/projects/editor/src/app/components/dialogs/label-edit-dialog.component.ts
@@ -0,0 +1,51 @@
+import { Component, Inject } from '@angular/core';
+import { MAT_DIALOG_DATA } from '@angular/material/dialog';
+import { TextImageLabel } from 'common/models/elements/element';
+import { FileService } from 'common/services/file.service';
+
+@Component({
+  selector: 'aspect-label-edit-dialog',
+  template: `
+    <mat-dialog-content fxLayout="column" fxLayoutGap="20px">
+      <aspect-rich-text-editor-simple [(content)]="newLabel.text">
+      </aspect-rich-text-editor-simple>
+
+      <div *ngIf="newLabel.imgSrc !== undefined" fxLayout="row" fxLayoutAlign="space-between center">
+        <div fxLayout="column" fxLayoutGap="10px">
+          <button mat-raised-button (click)="loadImage()">{{ 'loadImage' | translate }}</button>
+          <button mat-raised-button (click)="newLabel.imgSrc = null">{{ 'removeImage' | translate }}</button>
+          <mat-form-field>
+            <mat-label>{{'imagePosition' | translate }}</mat-label>
+            <mat-select [(ngModel)]="newLabel.imgPosition"
+                        [disabled]="newLabel.imgSrc == null">
+              <mat-option *ngFor="let option of ['above', 'below', 'left', 'right']"
+                          [value]="option">
+                {{ option | translate }}
+              </mat-option>
+            </mat-select>
+          </mat-form-field>
+        </div>
+        <img [src]="newLabel.imgSrc"
+             [style.object-fit]="'scale-down'"
+             [width]="200">
+      </div>
+
+    </mat-dialog-content>
+    <mat-dialog-actions>
+      <button mat-button [mat-dialog-close]="newLabel">{{'save' | translate }}</button>
+      <button mat-button mat-dialog-close>{{'cancel' | translate }}</button>
+    </mat-dialog-actions>
+  `,
+  styles: [
+    'aspect-rich-text-editor-simple {margin-bottom: 20px;}'
+  ]
+})
+export class LabelEditDialogComponent {
+  newLabel = { ...this.data.label };
+
+  constructor(@Inject(MAT_DIALOG_DATA) public data: { label: TextImageLabel }) { }
+
+  async loadImage(): Promise<void> {
+    this.newLabel.imgSrc = await FileService.loadImage();
+  }
+}
diff --git a/projects/editor/src/app/components/dialogs/likert-row-edit-dialog.component.ts b/projects/editor/src/app/components/dialogs/likert-row-edit-dialog.component.ts
index 86097006f19b3445197797fe7aaabba33fed729b..038fb8f3d0ddd73d22b9c3beb96adac6597cb925 100644
--- a/projects/editor/src/app/components/dialogs/likert-row-edit-dialog.component.ts
+++ b/projects/editor/src/app/components/dialogs/likert-row-edit-dialog.component.ts
@@ -2,41 +2,37 @@ import { Component, Inject } from '@angular/core';
 import { MAT_DIALOG_DATA } from '@angular/material/dialog';
 import { FileService } from 'common/services/file.service';
 import { LikertRowElement } from 'common/models/elements/compound-elements/likert/likert-row';
-import { TextImageLabel } from 'common/models/elements/element';
+import { TextLabel } from 'common/models/elements/element';
 
 @Component({
   selector: 'aspect-likert-row-edit-dialog',
   template: `
     <mat-dialog-content fxLayout="column">
-      <mat-form-field>
-        <mat-label>{{'text' | translate }}</mat-label>
-        <input #textField matInput type="text" [value]="data.row.rowLabel.text">
-      </mat-form-field>
+      <aspect-rich-text-editor-simple [(content)]="newLikertRow.rowLabel.text">
+      </aspect-rich-text-editor-simple>
 
-      <mat-form-field>
+      <mat-form-field [style.margin-top.px]="15">
         <mat-label>{{'id' | translate }}</mat-label>
-        <input #idField matInput type="text" [value]="data.row.id">
+        <input matInput type="text" [(ngModel)]="newLikertRow.id">
       </mat-form-field>
 
-      <button mat-raised-button (click)="loadImage()">{{ 'loadImage' | translate }}</button>
-      <button mat-raised-button (click)="imgSrc = null">{{ 'removeImage' | translate }}</button>
-      <img [src]="imgSrc"
-           [style.object-fit]="'scale-down'"
-           [width]="200">
+      <mat-checkbox [(ngModel)]="newLikertRow.readOnly">
+        {{'propertiesPanel.readOnly' | translate }}
+      </mat-checkbox>
 
       <mat-form-field appearance="fill">
-        <mat-label>{{'imagePosition' | translate }}</mat-label>
-        <mat-select #positionSelect [value]="data.row.rowLabel.position">
-          <mat-option *ngFor="let option of ['above', 'below', 'left', 'right']"
-                      [value]="option">
-            {{ option | translate }}
+        <mat-label>{{'preset' | translate }}</mat-label>
+        <mat-select [(ngModel)]="newLikertRow.value">
+          <mat-option [value]="null">{{'propertiesPanel.undefined' | translate }}</mat-option>
+          <mat-option *ngFor="let column of data.options; let i = index" [value]="i">
+            {{column.text}} (Index: {{i}})
           </mat-option>
         </mat-select>
       </mat-form-field>
 
       <mat-form-field appearance="fill">
         <mat-label>{{'verticalButtonAlignment' | translate }}</mat-label>
-        <mat-select #verticalButtonAlignmentSelect [value]="data.row.verticalButtonAlignment">
+        <mat-select [(ngModel)]="newLikertRow.verticalButtonAlignment">
           <mat-option *ngFor="let option of ['auto', 'center']"
                       [value]="option">
             {{ option | translate }}
@@ -44,40 +40,49 @@ import { TextImageLabel } from 'common/models/elements/element';
         </mat-select>
       </mat-form-field>
 
-      <mat-form-field appearance="fill">
-        <mat-label>{{'preset' | translate }}</mat-label>
-        <mat-select #valueField [value]="data.row.value">
-          <mat-option [value]="null">{{'propertiesPanel.undefined' | translate }}</mat-option>
-          <mat-option *ngFor="let column of data.columns; let i = index" [value]="i + 1">
-            {{column.text}} (Index: {{i + 1}})
-          </mat-option>
-        </mat-select>
-      </mat-form-field>
+      <div fxLayout="row" fxLayoutAlign="space-between center">
+        <div fxLayout="column" fxLayoutGap="10px">
+          <button mat-raised-button (click)="loadImage()">
+            {{ 'loadImage' | translate }}</button>
+          <button mat-raised-button (click)="newLikertRow.rowLabel.imgSrc = null">
+            {{ 'removeImage' | translate }}</button>
+          <mat-form-field>
+            <mat-label>{{'imagePosition' | translate }}</mat-label>
+            <mat-select [(ngModel)]="newLikertRow.rowLabel.imgPosition">
+              <mat-option *ngFor="let option of ['above', 'below', 'left', 'right']"
+                          [value]="option">
+                {{ option | translate }}
+              </mat-option>
+            </mat-select>
+          </mat-form-field>
+        </div>
+
+        <img [src]="newLikertRow.rowLabel.imgSrc"
+             [style.object-fit]="'scale-down'" [width]="200">
+      </div>
+
     </mat-dialog-content>
 
     <mat-dialog-actions>
-      <button mat-button
-              [mat-dialog-close]="{
-                rowLabel: {
-                  text: textField.value,
-                  imgSrc: imgSrc,
-                  position: positionSelect.value
-                },
-                id: idField.value,
-                value: valueField.value,
-                verticalButtonAlignment: verticalButtonAlignmentSelect.value
-              }">
+      <button mat-button [mat-dialog-close]="newLikertRow">
         {{'save' | translate }}
       </button>
       <button mat-button mat-dialog-close>{{'cancel' | translate }}</button>
     </mat-dialog-actions>
-  `
+  `,
+  styles: [
+    'mat-checkbox {margin-bottom: 15px;}'
+  ]
 })
 export class LikertRowEditDialogComponent {
-  constructor(@Inject(MAT_DIALOG_DATA) public data: { row: LikertRowElement, columns: TextImageLabel[] }) { }
-  imgSrc: string | null = this.data.row.rowLabel.imgSrc;
+  constructor(@Inject(MAT_DIALOG_DATA) public data: { row: LikertRowElement, options: TextLabel[] }) { }
+
+  newLikertRow = {
+    ...this.data.row,
+    rowLabel: { ...this.data.row.rowLabel }
+  };
 
   async loadImage(): Promise<void> {
-    this.imgSrc = await FileService.loadImage();
+    this.newLikertRow.rowLabel.imgSrc = await FileService.loadImage();
   }
 }
diff --git a/projects/editor/src/app/components/dialogs/rich-text-simple-edit-dialog.component.ts b/projects/editor/src/app/components/dialogs/rich-text-simple-edit-dialog.component.ts
index 04769292107e3fccacf83741e4c94dc25850126b..7e2c2a3cd053afcf8eff7ed128530889030cd644 100644
--- a/projects/editor/src/app/components/dialogs/rich-text-simple-edit-dialog.component.ts
+++ b/projects/editor/src/app/components/dialogs/rich-text-simple-edit-dialog.component.ts
@@ -1,18 +1,20 @@
 import { Component, Inject } from '@angular/core';
-import { MAT_DIALOG_DATA } from '@angular/material/dialog';
+import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
+import { TextLabel } from 'common/models/elements/element';
 
 @Component({
   selector: 'aspect-rich-text-simple-edit-dialog',
   template: `
-    <aspect-rich-text-editor-simple [(content)]="data.content"
+    <aspect-rich-text-editor-simple [(content)]="data.option.text"
                                     [defaultFontSize]="data.defaultFontSize">
     </aspect-rich-text-editor-simple>
     <mat-dialog-actions>
-      <button mat-button [mat-dialog-close]="data.content">{{'save' | translate }}</button>
+      <button mat-button [mat-dialog-close]="data.option">{{'save' | translate }}</button>
       <button mat-button mat-dialog-close>{{'cancel' | translate }}</button>
     </mat-dialog-actions>
   `
 })
 export class RichTextSimpleEditDialogComponent {
-  constructor(@Inject(MAT_DIALOG_DATA) public data: { content: string, defaultFontSize: number }) { }
+  constructor(public dialogRef: MatDialogRef<RichTextSimpleEditDialogComponent>,
+              @Inject(MAT_DIALOG_DATA) public data: { option: TextLabel, defaultFontSize: number }) { }
 }
diff --git a/projects/editor/src/app/components/new-ui-element-panel/ui-element-toolbox.component.ts b/projects/editor/src/app/components/new-ui-element-panel/ui-element-toolbox.component.ts
index baa034c751a2b6c792658788f91d61bf7dfc167d..5b9c08243c4aa2af123ae566aac5c7b58ff5aac8 100644
--- a/projects/editor/src/app/components/new-ui-element-panel/ui-element-toolbox.component.ts
+++ b/projects/editor/src/app/components/new-ui-element-panel/ui-element-toolbox.component.ts
@@ -1,7 +1,7 @@
 import { Component } from '@angular/core';
+import { UIElementType } from 'common/models/elements/element';
 import { UnitService } from '../../services/unit.service';
 import { SelectionService } from '../../services/selection.service';
-import { UIElementType } from 'common/models/elements/element';
 
 @Component({
   selector: 'aspect-ui-element-toolbox',
diff --git a/projects/editor/src/app/components/properties-panel/element-properties-panel.component.css b/projects/editor/src/app/components/properties-panel/element-properties-panel.component.css
new file mode 100644
index 0000000000000000000000000000000000000000..e6fe1a8d940edbfc3618d89712e9261b49559509
--- /dev/null
+++ b/projects/editor/src/app/components/properties-panel/element-properties-panel.component.css
@@ -0,0 +1,32 @@
+/*Make tabs not take more width than needed*/
+:host ::ng-deep .mat-tab-label {
+  min-width: 0 !important;
+}
+
+mat-tab-group {
+  overflow: auto;
+  padding: 0 10px;
+}
+
+.panel-title {
+  font-size: x-large;
+  text-align: center;
+}
+.panel-title span {
+  font-size: medium;
+}
+
+/*prevents small scrolling space around tab content*/
+:host ::ng-deep .mat-tab-body-wrapper {height: 100%}
+
+:host ::ng-deep .mat-form-field {
+  margin-bottom: -10px;
+}
+
+:host ::ng-deep mat-checkbox {
+  margin-bottom: 5px;
+}
+
+:host ::ng-deep .wide-form-field {
+  width: 100%;
+}
diff --git a/projects/editor/src/app/components/properties-panel/element-properties-panel.component.html b/projects/editor/src/app/components/properties-panel/element-properties-panel.component.html
index 5ea2dde8715b441e54844f0a0fceeae7c0b2b080..d7a996b467a72d2ed9fba2559822f0c216f2ecac 100644
--- a/projects/editor/src/app/components/properties-panel/element-properties-panel.component.html
+++ b/projects/editor/src/app/components/properties-panel/element-properties-panel.component.html
@@ -1,6 +1,6 @@
-<div *ngIf="selectedElements.length > 0"
-     class="properties-panel"
-     fxLayout="column" fxLayoutAlign="space-between stretch">
+<div *ngIf="selectedElements.length > 0 && combinedProperties"
+     class="properties-panel" fxFlexFill
+     fxLayout="column" fxLayoutAlign="start stretch">
   <div class="panel-title" fxLayout="column">
     <ng-container *ngIf="combinedProperties.type">
       {{'toolbox.' + combinedProperties.type | translate}}
@@ -10,8 +10,10 @@
       <i>Mehrfachauswahl</i>
     </ng-container>
   </div>
-  <mat-divider [style.margin-bottom]="0"></mat-divider>
-  <mat-tab-group mat-stretch-tabs>
+
+  <mat-divider></mat-divider>
+
+  <mat-tab-group mat-stretch-tabs fxFlex>
     <mat-tab>
       <ng-template mat-tab-label>
         <mat-icon class="example-tab-icon">build</mat-icon>
@@ -28,7 +30,7 @@
       </ng-template>
       <aspect-element-postion-properties [dimensions]="{ width: combinedProperties.width,
                                                          height: combinedProperties.height,
-                                                         dynamicWidth: $any(combinedProperties.dynamicWidth)}"
+                                                         dynamicWidth: $any(combinedProperties).dynamicWidth}"
                                          [positionProperties]="combinedProperties.position">
       </aspect-element-postion-properties>
     </mat-tab>
@@ -37,18 +39,23 @@
       <ng-template mat-tab-label>
         <mat-icon class="example-tab-icon">palette</mat-icon>
       </ng-template>
-      <aspect-element-style-properties [styles]="$any(combinedProperties.styling)">
-      </aspect-element-style-properties>
+        <aspect-element-style-properties [styles]="combinedProperties.styling">
+        </aspect-element-style-properties>
     </mat-tab>
   </mat-tab-group>
 
   <div fxLayout="column" class="button-group">
     <mat-divider></mat-divider>
-    <button mat-raised-button
+    <button mat-raised-button [disabled]="selectedElements.length > 1 ||
+                                          combinedProperties.type == 'toggle-button' ||
+                                          combinedProperties.type == 'drop-list-simple' ||
+                                          combinedProperties.type == 'text-field-simple'"
             (click)="duplicateElement()">
       {{'propertiesPanel.duplicateElement' | translate }}
     </button>
-    <button mat-raised-button color="warn"
+    <button mat-raised-button color="warn" [disabled]="combinedProperties.type == 'toggle-button' ||
+                                                       combinedProperties.type == 'drop-list-simple' ||
+                                                       combinedProperties.type == 'text-field-simple'"
             (click)="deleteElement()">
       {{'propertiesPanel.deleteElement' | translate }}
     </button>
diff --git a/projects/editor/src/app/components/properties-panel/element-properties-panel.component.ts b/projects/editor/src/app/components/properties-panel/element-properties-panel.component.ts
index 03c9afae47427e9e1cd3889f020204a79b05c908..323a3c0ac2c2f22e26633f5a8812b5d430163856 100644
--- a/projects/editor/src/app/components/properties-panel/element-properties-panel.component.ts
+++ b/projects/editor/src/app/components/properties-panel/element-properties-panel.component.ts
@@ -5,27 +5,22 @@ import { DomSanitizer } from '@angular/platform-browser';
 import { Subject } from 'rxjs';
 import { takeUntil } from 'rxjs/operators';
 import { TranslateService } from '@ngx-translate/core';
+import { MessageService } from 'common/services/message.service';
+import { TextLabel, UIElement } from 'common/models/elements/element';
+import { LikertRowElement } from 'common/models/elements/compound-elements/likert/likert-row';
 import { UnitService } from '../../services/unit.service';
 import { SelectionService } from '../../services/selection.service';
-import { MessageService } from 'common/services/message.service';
-import { DragNDropValueObject, TextImageLabel, UIElement } from 'common/models/elements/element';
+
+export type CombinedProperties = UIElement & { idList?: string[] };
 
 @Component({
   selector: 'aspect-element-properties',
   templateUrl: './element-properties-panel.component.html',
-  styles: [
-    '.button-group button {margin: 5px 10px;}',
-    'mat-divider {margin: 20px; border-top-width: 9px; border-top-style: dotted;}',
-    '.properties-panel {height: 100%; padding-bottom: 20px}',
-    '.properties-panel .mat-tab-group {height: 100%; overflow: auto; padding: 0 15px;}',
-    ':host ::ng-deep .mat-tab-body-wrapper {height: 100%}',
-    '.panel-title {font-size: x-large; text-align: center;}',
-    '.panel-title span {font-size: medium;}'
-  ]
+  styleUrls: ['./element-properties-panel.component.css']
 })
 export class ElementPropertiesPanelComponent implements OnInit, OnDestroy {
-  selectedElements!: UIElement[];
-  combinedProperties: UIElement = {} as UIElement;
+  selectedElements: UIElement[] = [];
+  combinedProperties: CombinedProperties | undefined;
   private ngUnsubscribe = new Subject<void>();
 
   constructor(private selectionService: SelectionService, public unitService: UnitService,
@@ -39,7 +34,7 @@ export class ElementPropertiesPanelComponent implements OnInit, OnDestroy {
       .subscribe(
         () => {
           this.combinedProperties =
-            ElementPropertiesPanelComponent.createCombinedProperties(this.selectedElements) as UIElement;
+            ElementPropertiesPanelComponent.createCombinedProperties(this.selectedElements);
         }
       );
     this.selectionService.selectedElements
@@ -48,14 +43,14 @@ export class ElementPropertiesPanelComponent implements OnInit, OnDestroy {
         (selectedElements: UIElement[]) => {
           this.selectedElements = selectedElements;
           this.combinedProperties =
-            ElementPropertiesPanelComponent.createCombinedProperties(this.selectedElements) as UIElement;
+            ElementPropertiesPanelComponent.createCombinedProperties(this.selectedElements);
         }
       );
   }
 
-  static createCombinedProperties(elements: UIElement[]): Partial<UIElement> {
+  static createCombinedProperties(elements: UIElement[]): CombinedProperties | undefined {
     if (elements.length > 0) {
-      const combinedProperties: Partial<UIElement> & { id: string | string[] } = { ...elements[0], id: elements[0].id };
+      const combinedProperties = { ...elements[0], idList: [elements[0].id] } as CombinedProperties;
 
       for (let elementCounter = 1; elementCounter < elements.length; elementCounter++) {
         const elementToMerge = elements[elementCounter];
@@ -64,14 +59,14 @@ export class ElementPropertiesPanelComponent implements OnInit, OnDestroy {
             if (typeof combinedProperties[property] === 'object' &&
               !Array.isArray(combinedProperties[property]) &&
               combinedProperties[property] !== null) {
-              (combinedProperties[property] as UIElement) =
+              combinedProperties[property] =
                 ElementPropertiesPanelComponent.createCombinedProperties(
                   [(combinedProperties[property] as UIElement),
                     (elementToMerge[property] as UIElement)]
-                ) as UIElement;
+                );
             } else if (JSON.stringify(combinedProperties[property]) !== JSON.stringify(elementToMerge[property])) {
               if (property === 'id') {
-                (combinedProperties.id as string[]).push(elementToMerge.id as string);
+                combinedProperties.idList?.push(elementToMerge.id as string);
               } else {
                 combinedProperties[property] = null;
               }
@@ -81,14 +76,17 @@ export class ElementPropertiesPanelComponent implements OnInit, OnDestroy {
           }
         });
       }
+      // replace rows array to trigger change detection for options panel
+      combinedProperties.rows = combinedProperties.rows ? [...combinedProperties.rows as LikertRowElement[]] : undefined;
+      // console.log('combi', combinedProperties);
       return combinedProperties;
     }
-    return {};
+    return undefined;
   }
 
   updateModel(property: string,
               value: string | number | boolean | string[] |
-              TextImageLabel[] | DragNDropValueObject[] | null,
+              TextLabel | TextLabel[] | LikertRowElement[] | null,
               isInputValid: boolean | null = true): void {
     if (isInputValid) {
       this.unitService.updateElementsProperty(this.selectedElements, property, value);
diff --git a/projects/editor/src/app/components/properties-panel/likert-row-label.pipe.ts b/projects/editor/src/app/components/properties-panel/likert-row-label.pipe.ts
new file mode 100644
index 0000000000000000000000000000000000000000..7aa2a01a352724b69a642f3c52d22391d7d4a540
--- /dev/null
+++ b/projects/editor/src/app/components/properties-panel/likert-row-label.pipe.ts
@@ -0,0 +1,13 @@
+import { Pipe, PipeTransform } from '@angular/core';
+import { LikertRowElement } from 'common/models/elements/compound-elements/likert/likert-row';
+import { TextImageLabel } from 'common/models/elements/element';
+
+@Pipe({
+  name: 'LikertRowLabel'
+})
+export class LikertRowLabelPipe implements PipeTransform {
+  // eslint-disable-next-line class-methods-use-this
+  transform(rows: LikertRowElement[]): TextImageLabel[] {
+    return rows.map(row => row.rowLabel);
+  }
+}
diff --git a/projects/editor/src/app/components/properties-panel/model-properties-tab/element-model-properties.component.css b/projects/editor/src/app/components/properties-panel/model-properties-tab/element-model-properties.component.css
index 1a581131d4f533a46cd6b2e8a289a5da07d9b83f..7b3c282c87ba1cae9103c55f390efb423f915b10 100644
--- a/projects/editor/src/app/components/properties-panel/model-properties-tab/element-model-properties.component.css
+++ b/projects/editor/src/app/components/properties-panel/model-properties-tab/element-model-properties.component.css
@@ -1,25 +1,34 @@
-.list-items {
-  padding: 5px 10px;
-  border-bottom: solid 1px #ccc;
-  display: flex;
-  flex-direction: row;
-  align-items: center;
-  justify-content: space-between
+aspect-input-element-properties {
+  margin-bottom: 10px;
 }
 
-::ng-deep aspect-element-properties .mat-tab-label {
-  min-width: 0 !important;
+button:not(.media-src-button):not(.mat-mini-fab):not(.mat-icon-button) {
+  width: 95%
 }
 
-::ng-deep aspect-element-properties .mat-tab-group {
-  padding: 15px;
+.mat-fab, .mat-raised-button {
+  margin-bottom: 10px;
 }
 
-:host ::ng-deep mat-button-toggle {
-  width: 100%;
-  height: 100%
+:host ::ng-deep fieldset {
+  margin-bottom: 15px;
 }
 
-button {
-  margin-bottom: 15px;
+:host ::ng-deep .drop-list {
+  border: solid 1px #ccc;
+  border-radius: 4px;
+}
+
+:host ::ng-deep .drop-list:empty {
+  border: none;
+}
+
+:host ::ng-deep .option-draggable {
+  border-bottom: solid 1px #ccc;
+  cursor: move;
+  padding: 3px 5px;
+}
+
+:host ::ng-deep .option-draggable:last-child {
+  border: none;
 }
diff --git a/projects/editor/src/app/components/properties-panel/model-properties-tab/element-model-properties.component.html b/projects/editor/src/app/components/properties-panel/model-properties-tab/element-model-properties.component.html
index 8765619a0905bc3708326556a1ba6af993c2ce43..f68424a4fce91ee5c1050860fbfa9f36fa2f0386 100644
--- a/projects/editor/src/app/components/properties-panel/model-properties-tab/element-model-properties.component.html
+++ b/projects/editor/src/app/components/properties-panel/model-properties-tab/element-model-properties.component.html
@@ -6,60 +6,56 @@
     <input matInput type="text" disabled *ngIf="selectedElements.length > 1" [value]="'Muss eindeutig sein'">
   </mat-form-field>
 
-  <mat-form-field *ngIf="combinedProperties.label !== undefined" appearance="fill">
+  <aspect-input-element-properties [combinedProperties]="combinedProperties"
+                                   (updateModel)="updateModel.emit($event)">
+  </aspect-input-element-properties>
+
+  <aspect-preset-value-properties [combinedProperties]="combinedProperties"
+                                  (updateModel)="updateModel.emit($event)">
+  </aspect-preset-value-properties>
+
+  <mat-form-field *ngIf="combinedProperties.label !== undefined && combinedProperties.required === undefined"
+                  appearance="fill">
     <mat-label>{{'propertiesPanel.label' | translate }}</mat-label>
     <input matInput type="text" [value]="$any(combinedProperties.label)"
            (input)="updateModel.emit({property: 'label', value: $any($event.target).value })">
   </mat-form-field>
 
-  <ng-container *ngIf="combinedProperties.document">
-    <button (click)="unitService.showDefaultEditDialog(selectedElements[0])">
-      <mat-icon>build_circle</mat-icon>
-    </button>
-  </ng-container>
-
-  <ng-container *ngIf="combinedProperties.player">
-    <button (click)="unitService.showDefaultEditDialog(selectedElements[0])">
-      <mat-icon>build_circle</mat-icon>
-    </button>
-  </ng-container>
-
-  <aspect-text-properties-field-set [combinedProperties]="combinedProperties"
-                                    (updateModel)="updateModel.emit($event)">
-  </aspect-text-properties-field-set>
-
-  <mat-checkbox *ngIf="combinedProperties.strikeOtherOptions !== undefined"
-                [checked]="$any(combinedProperties.strikeOtherOptions)"
-                (change)="updateModel.emit({ property: 'strikeOtherOptions', value: $event.checked })">
-    {{'propertiesPanel.strikeOtherOptions' | translate }}
-  </mat-checkbox>
-  <mat-checkbox *ngIf="combinedProperties.allowUnset !== undefined"
-                [checked]="$any(combinedProperties.allowUnset)"
-                (change)="updateModel.emit({ property: 'allowUnset', value: $event.checked })">
-    {{'propertiesPanel.allowUnset' | translate }}
-  </mat-checkbox>
-
-  <mat-checkbox *ngIf="combinedProperties.readOnly !== undefined"
-                [checked]="$any(combinedProperties.readOnly)"
-                (change)="updateModel.emit({ property: 'readOnly', value: $event.checked })">
-    {{'propertiesPanel.readOnly' | translate }}
-  </mat-checkbox>
-  <mat-checkbox *ngIf="combinedProperties.required !== undefined"
-                [checked]="$any(combinedProperties.required)"
-                (change)="updateModel.emit({ property: 'required', value: $event.checked })">
-    {{'propertiesPanel.requiredField' | translate }}
-  </mat-checkbox>
-  <mat-form-field *ngIf="combinedProperties.required"
-                  appearance="fill">
-    <mat-label>{{'propertiesPanel.requiredWarnMessage' | translate }}</mat-label>
-    <input matInput type="text" [value]="$any(combinedProperties.requiredWarnMessage)"
-           (input)="updateModel.emit({ property: 'requiredWarnMessage', value: $any($event.target).value })">
+  <mat-form-field *ngIf="combinedProperties.label2 !== undefined" appearance="fill">
+    <mat-label>{{'propertiesPanel.label2' | translate }}</mat-label>
+    <input matInput type="text" [value]="$any(combinedProperties.label2)"
+           (input)="updateModel.emit({property: 'label2', value: $any($event.target).value })">
   </mat-form-field>
 
   <aspect-options-field-set [combinedProperties]="combinedProperties"
                             (updateModel)="updateModel.emit($event)">
   </aspect-options-field-set>
 
+  <aspect-border-properties [combinedProperties]="combinedProperties"
+                            (updateModel)="updateModel.emit($event)"></aspect-border-properties>
+
+  <button *ngIf="combinedProperties.document"
+          mat-raised-button fxFlexAlign="center"
+          (click)="unitService.showDefaultEditDialog(selectedElements[0])">
+    Text editieren
+  </button>
+
+  <button *ngIf="combinedProperties.src"
+          mat-fab color="primary" fxFlexAlign="center" class="media-src-button"
+          [matTooltip]="'Medienquelle ändern'" [matTooltipPosition]="'right'"
+          (click)="changeMediaSrc(combinedProperties.type)">
+    <mat-icon>upload_file</mat-icon>
+  </button>
+  <button *ngIf="combinedProperties.player"
+          mat-raised-button fxFlexAlign="center"
+          (click)="unitService.showDefaultEditDialog(selectedElements[0])">
+    Medienoptionen
+  </button>
+
+  <aspect-text-properties-field-set [combinedProperties]="combinedProperties"
+                                    (updateModel)="updateModel.emit($event)">
+  </aspect-text-properties-field-set>
+
   <mat-form-field *ngIf="combinedProperties.alignment" appearance="fill">
     <mat-label>{{'propertiesPanel.alignment' | translate }}</mat-label>
     <mat-select [value]="combinedProperties.alignment"
@@ -71,6 +67,10 @@
     </mat-select>
   </mat-form-field>
 
+  <aspect-select-properties [combinedProperties]="combinedProperties"
+                             (updateModel)="updateModel.emit($event)">
+  </aspect-select-properties>
+
   <mat-checkbox *ngIf="combinedProperties.resizeEnabled !== undefined"
                 [checked]="$any(combinedProperties.resizeEnabled)"
                 (change)="updateModel.emit({ property: 'resizeEnabled', value: $event.checked })">
@@ -88,50 +88,13 @@
                             (updateModel)="updateModel.emit($event)">
   </aspect-button-properties>
 
-  <mat-form-field *ngIf="combinedProperties.options !== undefined && !combinedProperties.connectedTo"
-                  appearance="fill">
-    <mat-label>{{'preset' | translate }}</mat-label>
-    <mat-select [value]="combinedProperties.value"
-                (selectionChange)="updateModel.emit({ property: 'value', value: $event.value })">
-      <mat-option [value]="null">{{'propertiesPanel.undefined' | translate }}</mat-option>
-      <mat-option *ngFor="let option of $any(combinedProperties.options); let i = index" [value]="i">
-        {{option}} (Index: {{i}})
-      </mat-option>
-    </mat-select>
-  </mat-form-field>
-
-  <mat-form-field *ngIf="combinedProperties.richTextOptions !== undefined && !combinedProperties.connectedTo"
-                  appearance="fill">
-    <mat-label>{{'preset' | translate }}</mat-label>
-    <mat-select [value]="combinedProperties.value"
-                (selectionChange)="updateModel.emit({ property: 'value', value: $event.value })">
-      <mat-option [value]="null">{{'propertiesPanel.undefined' | translate }}</mat-option>
-      <mat-option *ngFor="let option of $any(combinedProperties.richTextOptions); let i = index" [value]="i"
-      [innerHTML]="option + '&nbsp;(Index: ' + i + ')'">
-      </mat-option>
-    </mat-select>
-  </mat-form-field>
-
-  <!-- This is for radio with images-->
-  <mat-form-field *ngIf="combinedProperties.columns !== undefined && combinedProperties.rows === undefined"
-                  appearance="fill">
-    <mat-label>{{'preset' | translate }}</mat-label>
-    <mat-select [value]="combinedProperties.value"
-                (selectionChange)="updateModel.emit({ property: 'value', value: $event.value })">
-      <mat-option [value]="null">{{'propertiesPanel.undefined' | translate }}</mat-option>
-      <mat-option *ngFor="let column of $any(combinedProperties.columns); let i = index" [value]="i">
-        {{column.name}} (Index: {{i}})
-      </mat-option>
-    </mat-select>
-  </mat-form-field>
-
   <aspect-slider-properties [combinedProperties]="combinedProperties"
                             (updateModel)="updateModel.emit($event)">
   </aspect-slider-properties>
 
-  <ng-container *ngIf="combinedProperties.value === true || combinedProperties.value === false">
+  <ng-container *ngIf="combinedProperties.type === 'checkbox'">
     {{'preset' | translate }}
-    <mat-button-toggle-group [value]="combinedProperties.value"
+    <mat-button-toggle-group [value]="combinedProperties.value" fxFlexAlign="start"
                              (change)="updateModel.emit({ property: 'value', value: $event.value })">
       <mat-button-toggle [value]="true">{{'propertiesPanel.true' | translate }}</mat-button-toggle>
       <mat-button-toggle [value]="false">{{'propertiesPanel.false' | translate }}</mat-button-toggle>
@@ -147,96 +110,21 @@
                     isInputValid: presetValue.valid})">
   </mat-form-field>
 
-  <mat-form-field *ngIf="combinedProperties.type === 'text-area'"
-                  appearance="fill">
-    <mat-label>{{'preset' | translate }}</mat-label>
-    <textarea matInput type="text"
-              [value]="$any(combinedProperties.value)"
-              (input)="updateModel.emit({ property: 'value', value: $any($event.target).value })">
-            </textarea>
-  </mat-form-field>
+  <aspect-text-field-element-properties [combinedProperties]="combinedProperties"
+                                        (updateModel)="updateModel.emit($event)">
+  </aspect-text-field-element-properties>
 
-  <mat-form-field *ngIf="combinedProperties.type === 'text-field'"
+  <mat-form-field *ngIf="combinedProperties.firstColumnSizeRatio != null"
+                  matTooltip="{{'propertiesPanel.firstColumnSizeRatioExplanation' | translate }}"
                   appearance="fill">
-    <mat-label>{{'preset' | translate }}</mat-label>
-    <input matInput type="text" [value]="$any(combinedProperties.value)"
-           (input)="updateModel.emit({property: 'value', value: $any($event.target).value })">
-  </mat-form-field>
-
-  <aspect-input-element-properties [combinedProperties]="combinedProperties"
-                                   (updateModel)="updateModel.emit($event)">
-  </aspect-input-element-properties>
-
-  <mat-form-field disabled="true" *ngIf="combinedProperties.rows !== undefined">
-    <ng-container>
-      <mat-label>{{'rows' | translate }}</mat-label>
-      <div class="drop-list" cdkDropList [cdkDropListData]="combinedProperties.rows"
-           (cdkDropListDropped)="moveListValue('rows', $any($event))">
-        <div *ngFor="let row of $any(combinedProperties.rows); let i = index" cdkDrag
-             class="list-items" fxLayout="row" fxLayoutAlign="end center">
-          <div fxFlex="70">
-            {{row.rowLabel.text}}
-          </div>
-          <img [src]="row.rowLabel.imgSrc"
-               [style.object-fit]="'scale-down'"
-               [style.height.px]="40">
-          <button mat-icon-button color="primary"
-                  (click)="editLikertRow(i)">
-            <mat-icon>build</mat-icon>
-          </button>
-          <button mat-icon-button color="primary"
-                  (click)="removeListValue('rows', row)">
-            <mat-icon>clear</mat-icon>
-          </button>
-        </div>
-      </div>
-    </ng-container>
-    <div fxLayout="row" fxLayoutAlign="center center">
-      <button mat-icon-button matPrefix
-              (click)="addLikertRow(newRow.value); newRow.select()">
-        <mat-icon>add</mat-icon>
-      </button>
-      <input #newRow matInput type="text" placeholder="Fragetext"
-             (keyup.enter)="addLikertRow(newRow.value); newRow.select()">
-    </div>
-  </mat-form-field>
-
-  <mat-form-field disabled="true" *ngIf="combinedProperties.columns !== undefined">
-    <ng-container>
-      <mat-label>{{'columns' | translate }}</mat-label>
-      <div class="drop-list" cdkDropList [cdkDropListData]="combinedProperties.columns"
-           (cdkDropListDropped)="moveListValue('columns', $any($event))">
-        <div *ngFor="let column of $any(combinedProperties.columns); let i = index" cdkDrag
-             class="list-items" fxLayout="row" fxLayoutAlign="end center">
-          <div fxFlex="70" [innerHTML]="sanitizer.bypassSecurityTrustHtml(column.text)">
-          </div>
-          <img [src]="column.imgSrc"
-               [style.object-fit]="'scale-down'"
-               [style.height.px]="40">
-          <button mat-icon-button color="primary"
-                  (click)="editColumnOption(i)">
-            <mat-icon>build</mat-icon>
-          </button>
-          <button mat-icon-button color="primary"
-                  (click)="removeListValue('columns', column)">
-            <mat-icon>clear</mat-icon>
-          </button>
-        </div>
-      </div>
-    </ng-container>
-    <div fxLayout="row" fxLayoutAlign="center center">
-      <button mat-icon-button matPrefix
-              (click)="addColumn(newColumn.value); newColumn.select()">
-        <mat-icon>add</mat-icon>
-      </button>
-      <input #newColumn matInput type="text" placeholder="Antworttext"
-             (keyup.enter)="addColumn(newColumn.value); newColumn.select()">
-    </div>
+    <mat-label>{{'propertiesPanel.firstColumnSizeRatio' | translate }}</mat-label>
+    <input matInput type="number" [value]="$any(combinedProperties.firstColumnSizeRatio)"
+           (input)="updateModel.emit({ property: 'firstColumnSizeRatio', value: $any($event.target).value })">
   </mat-form-field>
 
-  <aspect-image-properties [combinedProperties]="combinedProperties"
-                           (updateModel)="updateModel.emit($event)">
-  </aspect-image-properties>
+  <aspect-scale-and-zoom-properties [combinedProperties]="combinedProperties"
+                                    (updateModel)="updateModel.emit($event)">
+  </aspect-scale-and-zoom-properties>
 
   <mat-checkbox *ngIf="combinedProperties.verticalOrientation !== undefined"
                 [checked]="$any(combinedProperties.verticalOrientation)"
@@ -247,12 +135,4 @@
   <aspect-drop-list-properties [combinedProperties]="combinedProperties"
                                (updateModel)="updateModel.emit($event)">
   </aspect-drop-list-properties>
-
-  <mat-form-field *ngIf="combinedProperties.firstColumnSizeRatio != null"
-                  matTooltip="{{'propertiesPanel.firstColumnSizeRatioExplanation' | translate }}"
-                  appearance="fill" class="mdInput textsingleline">
-    <mat-label>{{'propertiesPanel.firstColumnSizeRatio' | translate }}</mat-label>
-    <input matInput type="number" [value]="$any(combinedProperties.firstColumnSizeRatio)"
-           (input)="updateModel.emit({ property: 'firstColumnSizeRatio', value: $any($event.target).value })">
-  </mat-form-field>
 </div>
diff --git a/projects/editor/src/app/components/properties-panel/model-properties-tab/element-model-properties.component.ts b/projects/editor/src/app/components/properties-panel/model-properties-tab/element-model-properties.component.ts
index e176e705013d2438636f64bc98d772c40b1ba16b..2e3c11fe6b26b66dc4296181ef3bab43a0ff9992 100644
--- a/projects/editor/src/app/components/properties-panel/model-properties-tab/element-model-properties.component.ts
+++ b/projects/editor/src/app/components/properties-panel/model-properties-tab/element-model-properties.component.ts
@@ -2,16 +2,18 @@ import {
   Component, EventEmitter,
   Input, Output
 } from '@angular/core';
+import { DomSanitizer } from '@angular/platform-browser';
 import { CdkDragDrop } from '@angular/cdk/drag-drop/drag-events';
 import { moveItemInArray } from '@angular/cdk/drag-drop';
+import {
+  InputElementValue, TextLabel, TextImageLabel, UIElement
+} from 'common/models/elements/element';
+import { LikertRowElement } from 'common/models/elements/compound-elements/likert/likert-row';
+import { FileService } from 'common/services/file.service';
+import { CombinedProperties } from 'editor/src/app/components/properties-panel/element-properties-panel.component';
 import { UnitService } from '../../../services/unit.service';
 import { SelectionService } from '../../../services/selection.service';
 import { DialogService } from '../../../services/dialog.service';
-import { DomSanitizer } from '@angular/platform-browser';
-import { DragNDropValueObject, InputElementValue, TextImageLabel, UIElement } from 'common/models/elements/element';
-import { LikertRowElement } from 'common/models/elements/compound-elements/likert/likert-row';
-import { LikertElement } from 'common/models/elements/compound-elements/likert/likert';
-import { IDManager } from 'common/util/id-manager';
 
 @Component({
   selector: 'aspect-element-model-properties-component',
@@ -19,11 +21,11 @@ import { IDManager } from 'common/util/id-manager';
   styleUrls: ['./element-model-properties.component.css']
 })
 export class ElementModelPropertiesComponent {
-  @Input() combinedProperties: UIElement = {} as UIElement;
+  @Input() combinedProperties!: CombinedProperties;
   @Input() selectedElements: UIElement[] = [];
   @Output() updateModel = new EventEmitter<{
     property: string;
-    value: InputElementValue | TextImageLabel[] | DragNDropValueObject[],
+    value: InputElementValue | TextImageLabel[] | LikertRowElement[] | TextLabel[],
     isInputValid?: boolean | null
   }>();
 
@@ -44,12 +46,6 @@ export class ElementModelPropertiesComponent {
     this.updateModel.emit({ property: property, value: event.container.data });
   }
 
-  removeListValue(property: string, option: any): void {
-    const valueList = this.combinedProperties[property] as string[] | LikertRowElement[] | TextImageLabel[];
-    valueList.splice(valueList.indexOf(option), 1);
-    this.updateModel.emit({ property: property, value: valueList });
-  }
-
   async editTextOption(property: string, optionIndex: number): Promise<void> {
     const oldOptions = this.selectionService.getSelectedElements()[0][property] as string[];
     await this.dialogService.showTextEditDialog(oldOptions[optionIndex])
@@ -61,75 +57,20 @@ export class ElementModelPropertiesComponent {
       });
   }
 
-  async editColumnOption(optionIndex: number): Promise<void> {
-    const firstElement = (this.selectedElements as LikertElement[])[0];
-    await this.dialogService
-      .showLikertColumnEditDialog(firstElement.columns[optionIndex],
-        (this.combinedProperties as LikertElement).styling.fontSize)
-      .subscribe((result: TextImageLabel) => {
-        if (result) {
-          firstElement.columns[optionIndex] = result;
-          this.updateModel.emit({ property: 'columns', value: firstElement.columns });
-        }
-      });
-  }
-
-  addColumn(value: string): void {
-    const column: TextImageLabel = {
-      text: value,
-      imgSrc: null,
-      position: 'above'
-    };
-    (this.combinedProperties.columns as TextImageLabel[]).push(column);
-    this.updateModel.emit({ property: 'columns', value: this.combinedProperties.columns as TextImageLabel[] });
-  }
-
-  addLikertRow(rowLabelText: string): void {
-    const newRow = new LikertRowElement({
-      type: 'likert-row',
-      rowLabel: {
-        text: rowLabelText,
-        imgSrc: null,
-        position: 'above'
-      },
-      columnCount: (this.combinedProperties.columns as TextImageLabel[]).length
-    }, IDManager.getInstance());
-    (this.combinedProperties.rows as LikertRowElement[]).push(newRow);
-    this.updateModel.emit({ property: 'rows', value: this.combinedProperties.rows as LikertRowElement[] });
-  }
-
-  async editLikertRow(rowIndex: number): Promise<void> {
-    const row = (this.combinedProperties.rows as LikertRowElement[])[rowIndex] as LikertRowElement;
-    const columns = this.combinedProperties.columns as TextImageLabel[];
-
-    await this.dialogService.showLikertRowEditDialog(row, columns)
-      .subscribe((result: LikertRowElement) => {
-        if (result) {
-          if (result.id !== row.id) {
-            this.unitService.updateElementsProperty(
-              [row],
-              'id',
-              result.id
-            );
-          }
-          if (result.rowLabel !== row.rowLabel) {
-            this.unitService.updateElementsProperty([row], 'rowLabel', result.rowLabel);
-          }
-          if (result.value !== row.value) {
-            this.unitService.updateElementsProperty(
-              [row],
-              'value',
-              result.value
-            );
-          }
-          if (result.verticalButtonAlignment !== row.verticalButtonAlignment) {
-            this.unitService.updateElementsProperty(
-              [row],
-              'verticalButtonAlignment',
-              result.verticalButtonAlignment
-            );
-          }
-        }
-      });
+  async changeMediaSrc(elementType: string) {
+    let mediaSrc = '';
+    switch (elementType) {
+      case 'image':
+        mediaSrc = await FileService.loadImage();
+        break;
+      case 'audio':
+        mediaSrc = await FileService.loadAudio();
+        break;
+      case 'video':
+        mediaSrc = await FileService.loadVideo();
+        break;
+      // no default
+    }
+    this.updateModel.emit({ property: 'src', value: mediaSrc });
   }
 }
diff --git a/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/border-properties.component.ts b/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/border-properties.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..19c59bc7d7d3b4f461944b19ed351e4c2eef4269
--- /dev/null
+++ b/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/border-properties.component.ts
@@ -0,0 +1,37 @@
+import {
+  Component, EventEmitter, Input, Output
+} from '@angular/core';
+import { UIElement } from 'common/models/elements/element';
+
+@Component({
+  selector: 'aspect-border-properties',
+  template: `
+    <div fxLayout="column">
+      <mat-checkbox *ngIf="combinedProperties.hasBorderTop !== undefined"
+                    [checked]="$any(combinedProperties).hasBorderTop"
+                    (change)="updateModel.emit({ property: 'hasBorderTop', value: $event.checked })">
+        {{'propertiesPanel.hasBorderTop' | translate }}
+      </mat-checkbox>
+      <mat-checkbox *ngIf="combinedProperties.hasBorderBottom !== undefined"
+                    [checked]="$any(combinedProperties).hasBorderBottom"
+                    (change)="updateModel.emit({ property: 'hasBorderBottom', value: $event.checked })">
+        {{'propertiesPanel.hasBorderBottom' | translate }}
+      </mat-checkbox>
+      <mat-checkbox *ngIf="combinedProperties.hasBorderLeft !== undefined"
+                    [checked]="$any(combinedProperties).hasBorderLeft"
+                    (change)="updateModel.emit({ property: 'hasBorderLeft', value: $event.checked })">
+        {{'propertiesPanel.hasBorderLeft' | translate }}
+      </mat-checkbox>
+      <mat-checkbox *ngIf="combinedProperties.hasBorderRight !== undefined"
+                    [checked]="$any(combinedProperties).hasBorderRight"
+                    (change)="updateModel.emit({ property: 'hasBorderRight', value: $event.checked })">
+        {{'propertiesPanel.hasBorderRight' | translate }}
+      </mat-checkbox>
+    </div>
+  `
+})
+export class BorderPropertiesComponent {
+  @Input() combinedProperties!: UIElement;
+  @Output() updateModel =
+    new EventEmitter<{ property: string; value: string | number | boolean | null }>();
+}
diff --git a/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/button-properties.component.ts b/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/button-properties.component.ts
index 8db4f5d8a51aa0b2db10488b30e95a7b7826aa3d..8f97aba55f496d5e8e66b83a28b1028894fa0bb1 100644
--- a/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/button-properties.component.ts
+++ b/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/button-properties.component.ts
@@ -1,11 +1,10 @@
 import {
-  Component, EventEmitter, Input, OnInit, Output
+  Component, EventEmitter, Input, Output
 } from '@angular/core';
-import { UnitService } from '../../../../services/unit.service';
-import { SelectionService } from '../../../../services/selection.service';
 import { FileService } from 'common/services/file.service';
 import { UIElement } from 'common/models/elements/element';
-import { ButtonElement } from 'common/models/elements/button/button';
+import { UnitService } from '../../../../services/unit.service';
+import { SelectionService } from '../../../../services/selection.service';
 
 @Component({
   selector: 'aspect-button-properties',
@@ -14,14 +13,14 @@ import { ButtonElement } from 'common/models/elements/button/button';
       <legend>Knopf</legend>
 
       <mat-checkbox *ngIf="combinedProperties.asLink !== undefined"
-                    [checked]="combinedButtonElement.asLink"
+                    [checked]="$any(combinedProperties).asLink"
                     (change)="updateModel.emit({ property: 'asLink', value: $event.checked })">
         {{'propertiesPanel.asLink' | translate }}
       </mat-checkbox>
 
       <mat-form-field *ngIf="combinedProperties.action !== undefined" appearance="fill">
         <mat-label>{{'propertiesPanel.action' | translate }}</mat-label>
-        <mat-select [value]="combinedButtonElement.action"
+        <mat-select [value]="combinedProperties.action"
                     (selectionChange)="updateModel.emit({ property: 'action', value: $event.value })">
           <mat-option [value]="null">
             {{ 'propertiesPanel.none' | translate }}
@@ -35,13 +34,13 @@ import { ButtonElement } from 'common/models/elements/button/button';
 
       <mat-form-field appearance="fill">
         <mat-label>{{'propertiesPanel.actionParam' | translate }}</mat-label>
-          <mat-select [disabled]="combinedButtonElement.action === null"
-                      [value]="combinedButtonElement.actionParam"
-                      [matTooltipDisabled]="combinedButtonElement.action !== 'pageNav'"
+          <mat-select [disabled]="combinedProperties.action === null"
+                      [value]="combinedProperties.actionParam"
+                      [matTooltipDisabled]="combinedProperties.action !== 'pageNav'"
                       [matTooltip]="'propertiesPanel.pageNavSelectionHint' | translate"
                       (selectionChange)="updateModel.emit({ property: 'actionParam', value: $event.value })">
 
-            <ng-container *ngIf="combinedButtonElement.action === 'pageNav'">
+            <ng-container *ngIf="combinedProperties.action === 'pageNav'">
               <ng-container *ngFor="let page of unitService.unit.pages; index as i">
                 <mat-option *ngIf="!page.alwaysVisible && selectionService.selectedPageIndex !== i"
                             [value]="i">
@@ -50,7 +49,7 @@ import { ButtonElement } from 'common/models/elements/button/button';
               </ng-container>
             </ng-container>
 
-            <ng-container *ngIf="combinedButtonElement.action === 'unitNav'">
+            <ng-container *ngIf="combinedProperties.action === 'unitNav'">
               <mat-option *ngFor="let option of [undefined, 'previous', 'next', 'first', 'last', 'end']"
                           [value]="option">
                 {{ 'propertiesPanel.' + option | translate }}
@@ -60,40 +59,27 @@ import { ButtonElement } from 'common/models/elements/button/button';
       </mat-form-field>
 
       <div class="image-panel" (mouseenter)="hoveringImage = true" (mouseleave)="hoveringImage = false">
-        <button *ngIf="combinedButtonElement.imageSrc === null || hoveringImage"
+        <button *ngIf="combinedProperties.imageSrc === null || hoveringImage"
                 class="add-image-button" mat-raised-button
                 (click)="loadImage()">{{'loadImage' | translate }}</button>
-        <button *ngIf="combinedButtonElement.imageSrc !== null && hoveringImage"
+        <button *ngIf="combinedProperties.imageSrc !== null && hoveringImage"
                 class="remove-image-button" mat-raised-button
                 (click)="removeImage()">{{'removeImage' | translate }}</button>
-        <img *ngIf="combinedButtonElement.imageSrc"
-             [src]="combinedButtonElement.imageSrc">
+        <img *ngIf="combinedProperties.imageSrc"
+             [src]="combinedProperties.imageSrc">
       </div>
     </fieldset>
-  `,
-  styles: [
-    'mat-checkbox {margin-bottom: 10px;}',
-    'mat-form-field {width: 100%;}',
-    '.image-panel {width: 250px; height: 150px; border: 1px solid; text-align: center; position: relative;}',
-    '.image-panel .add-image-button {position: absolute; left: 50%; top: 35%; transform: translate(-50%, -35%);}',
-    '.image-panel .remove-image-button {position: absolute; left: 50%; top: 70%; transform: translate(-50%, -70%);}',
-    '.image-panel img {width:100%; height:100%;}'
-  ]
+  `
 })
-export class ButtonPropertiesComponent implements OnInit {
+export class ButtonPropertiesComponent {
   @Input() combinedProperties!: UIElement;
   @Output() updateModel =
     new EventEmitter<{ property: string; value: string | number | boolean | null, isInputValid?: boolean | null }>();
 
-  combinedButtonElement: ButtonElement = {} as ButtonElement;
   hoveringImage = false;
 
   constructor(public unitService: UnitService, public selectionService: SelectionService) { }
 
-  ngOnInit(): void {
-    this.combinedButtonElement = this.combinedProperties as ButtonElement;
-  }
-
   async loadImage(): Promise<void> {
     this.updateModel.emit({ property: 'imageSrc', value: await FileService.loadImage() });
   }
diff --git a/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/drop-list-properties.component.ts b/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/drop-list-properties.component.ts
index dcf7b37f87d41e71e3e2d40237c3dcc0ffe9ff3e..b0ada6e195600aecb61a6111716339eaa5400cb3 100644
--- a/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/drop-list-properties.component.ts
+++ b/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/drop-list-properties.component.ts
@@ -1,63 +1,38 @@
 import {
   Component, EventEmitter, Input, Output
 } from '@angular/core';
-import { UnitService } from '../../../../services/unit.service';
-import { SelectionService } from '../../../../services/selection.service';
-import { DialogService } from '../../../../services/dialog.service';
-import { MessageService } from 'common/services/message.service';
 import { TranslateService } from '@ngx-translate/core';
-import { CdkDragDrop } from '@angular/cdk/drag-drop/drag-events';
 import { moveItemInArray } from '@angular/cdk/drag-drop';
-import { DragNDropValueObject } from 'common/models/elements/element';
+import { MessageService } from 'common/services/message.service';
+import { DragNDropValueObject, TextImageLabel } from 'common/models/elements/element';
 import { IDManager } from 'common/util/id-manager';
+import { CombinedProperties } from 'editor/src/app/components/properties-panel/element-properties-panel.component';
+import { UnitService } from '../../../../services/unit.service';
+import { SelectionService } from '../../../../services/selection.service';
+import { DialogService } from '../../../../services/dialog.service';
 
 @Component({
   selector: 'aspect-drop-list-properties',
   template: `
-    <fieldset *ngIf="combinedProperties.type === 'drop-list' ||
-                     combinedProperties.type === 'drop-list-simple'">
-      <legend>Ablegeliste</legend>
-
-      <div class="value-list-container">
-        <mat-label>{{'preset' | translate }}</mat-label>
-        <div class="drop-list" cdkDropList [cdkDropListData]="combinedProperties.value"
-             (cdkDropListDropped)="moveListValue($any($event))">
-          <div *ngFor="let value of $any(combinedProperties.value); let i = index" cdkDrag
-               class="list-items" fxLayout="row" fxLayoutAlign="end center">
-            <div fxFlex="70" class="draggable-element-label">
-              {{value.stringValue}} ({{value.id}})
-            </div>
-            <img [src]="value.imgSrcValue"
-                 [style.object-fit]="'scale-down'"
-                 [style.height.px]="40">
-            <button mat-icon-button color="primary"
-                    (click)="editDropListOption(i)">
-              <mat-icon>build</mat-icon>
-            </button>
-            <button mat-icon-button color="primary"
-                    (click)="removeListValue('value', i)">
-              <mat-icon>clear</mat-icon>
-            </button>
-          </div>
-        </div>
-        <div fxLayout="row" fxLayoutAlign="center center" class="text-area-container">
-          <textarea matInput type="text"
-                    #newValue rows="2"
-                    (keyup.enter)="addDropListOption(newValue.value); newValue.select()"></textarea>
-          <button mat-icon-button
-                  (click)="addDropListOption(newValue.value); newValue.select()">
-            <mat-icon>add</mat-icon>
-          </button>
-        </div>
-      </div>
-
-      <mat-form-field appearance="fill" *ngIf="combinedProperties.connectedTo !== null"
+    <div *ngIf="combinedProperties.type === 'drop-list' ||
+                combinedProperties.type === 'drop-list-simple'"
+                fxLayout="column">
+      <aspect-option-list-panel [title]="'preset'" [textFieldLabel]="'Neue Option'"
+                                [itemList]="$any(combinedProperties.value)"
+                                (addItem)="addOption($event)"
+                                (removeItem)="removeOption($event)"
+                                (changedItemOrder)="moveOption('value', $event)"
+                                (editItem)="editOption($event)">
+      </aspect-option-list-panel>
+
+      <mat-form-field *ngIf="combinedProperties.connectedTo !== null"
+                      class="wide-form-field" appearance="fill"
                       (click)="generateValidDropLists()">
         <mat-label>{{'propertiesPanel.connectedDropLists' | translate }}</mat-label>
         <mat-select multiple [ngModel]="combinedProperties.connectedTo"
                     (ngModelChange)="toggleConnectedDropList($event)">
           <mat-select-trigger>
-            {{'propertiesPanel.connectedDropLists' | translate }} ({{combinedProperties.connectedTo.length}})
+            {{'propertiesPanel.connectedDropLists' | translate }} ({{$any(combinedProperties.connectedTo).length}})
           </mat-select-trigger>
           <mat-option *ngFor="let id of dropListIDs" [value]="id">
             {{id}}
@@ -94,28 +69,20 @@ import { IDManager } from 'common/util/id-manager';
                     (change)="updateModel.emit({ property: 'highlightReceivingDropList', value: $event.checked })">
         {{'propertiesPanel.highlightReceivingDropList' | translate }}
       </mat-checkbox>
-      <mat-form-field *ngIf="combinedProperties.highlightReceivingDropList"
-                      appearance="fill" class="mdInput textsingleline">
+      <mat-form-field appearance="fill" class="mdInput textsingleline">
         <mat-label>{{'propertiesPanel.highlightReceivingDropListColor' | translate }}</mat-label>
-        <input matInput type="text" [value]="$any(combinedProperties.highlightReceivingDropListColor)"
+        <input matInput type="text"
+               [disabled]="!combinedProperties.highlightReceivingDropList"
+               [value]="$any(combinedProperties.highlightReceivingDropListColor)"
                (input)="updateModel.emit({
                      property: 'highlightReceivingDropListColor',
                      value: $any($event.target).value })">
       </mat-form-field>
-    </fieldset>
-  `,
-  styles: [
-    'mat-form-field {width: 100%;}',
-    '.draggable-element-label {overflow-wrap: anywhere;}',
-    'mat-select {height: 100%;}',
-    '.text-area-container {background-color: lightgray; margin-bottom: 15px;}',
-    '.value-list-container {background-color: rgba(0,0,0,.04);}',
-    '.text-area-container button {border: 1px solid gray;}',
-    '.value-list-container mat-label {font-size: large;}'
-  ]
+    </div>
+  `
 })
 export class DropListPropertiesComponent {
-  @Input() combinedProperties!: any;
+  @Input() combinedProperties!: CombinedProperties;
   @Output() updateModel = new EventEmitter<{
     property: string;
     value: string | number | boolean | string[] | DragNDropValueObject[],
@@ -130,18 +97,34 @@ export class DropListPropertiesComponent {
               private messageService: MessageService,
               private translateService: TranslateService) { }
 
-  addDropListOption(value: string): void {
+  notifyListChange(changedList: DragNDropValueObject[]): void {
+    this.updateModel.emit({ property: 'value', value: changedList });
+  }
+
+  addOption(value: string): void {
     this.updateModel.emit({
       property: 'value',
       value: [
         ...this.combinedProperties.value as DragNDropValueObject[],
-        { stringValue: value, id: this.unitService.getNewValueID() } // TODO direkt IDService
+        {
+          text: value,
+          imgSrc: null,
+          imgPosition: 'above',
+          id: this.unitService.getNewValueID()
+        }
       ]
     });
   }
 
-  async editDropListOption(optionIndex: number): Promise<void> {
-    const oldOptions = this.combinedProperties.value;
+  moveOption(property: string, indices: { previousIndex: number, currentIndex: number }): void {
+    moveItemInArray(this.combinedProperties[property] as TextImageLabel[],
+      indices.previousIndex,
+      indices.currentIndex);
+    this.updateModel.emit({ property: property, value: this.combinedProperties[property] as DragNDropValueObject[] });
+  }
+
+  async editOption(optionIndex: number): Promise<void> {
+    const oldOptions: DragNDropValueObject[] = this.combinedProperties.value as DragNDropValueObject[];
 
     await this.dialogService.showDropListOptionEditDialog(oldOptions[optionIndex])
       .subscribe((result: DragNDropValueObject) => {
@@ -156,15 +139,10 @@ export class DropListPropertiesComponent {
       });
   }
 
-  moveListValue(event: CdkDragDrop<string[]>): void {
-    moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
-    this.updateModel.emit({ property: 'value', value: event.container.data });
-  }
-
-  removeListValue(property: string, optionIndex: number): void {
-    const valueList = this.combinedProperties[property] as DragNDropValueObject[];
+  removeOption(optionIndex: number): void {
+    const valueList = this.combinedProperties.value as DragNDropValueObject[];
     valueList.splice(optionIndex, 1);
-    this.updateModel.emit({ property: property, value: valueList });
+    this.updateModel.emit({ property: 'value', value: valueList });
   }
 
   toggleConnectedDropList(connectedDropListList: string[]) {
@@ -176,6 +154,6 @@ export class DropListPropertiesComponent {
 
   generateValidDropLists() {
     this.dropListIDs = this.unitService.getDropListElementIDs()
-      .filter(dropListID => !this.combinedProperties.id.includes(dropListID));
+      .filter(dropListID => !this.combinedProperties.idList!.includes(dropListID));
   }
 }
diff --git a/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/image-properties.component.ts b/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/image-properties.component.ts
deleted file mode 100644
index d5840779fb1199d2c83b4fb43ab34c355ed5f410..0000000000000000000000000000000000000000
--- a/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/image-properties.component.ts
+++ /dev/null
@@ -1,46 +0,0 @@
-import {
-  Component, EventEmitter, Input, Output
-} from '@angular/core';
-
-@Component({
-  selector: 'aspect-image-properties',
-  template: `
-    <mat-checkbox *ngIf="combinedProperties.scale !== undefined"
-                  [checked]="$any(combinedProperties.scale)"
-                  (change)="updateModel.emit({ property: 'scale', value: $event.checked })">
-      {{'propertiesPanel.scale' | translate }}
-    </mat-checkbox>
-
-    <mat-checkbox *ngIf="combinedProperties.magnifier !== undefined"
-                  [checked]="$any(combinedProperties.magnifier)"
-                  (change)="updateModel.emit({ property: 'magnifier', value: $event.checked })">
-      {{'propertiesPanel.magnifier' | translate }}
-    </mat-checkbox>
-    <mat-form-field *ngIf="combinedProperties.magnifier" appearance="fill">
-      <mat-label>{{'propertiesPanel.magnifierSize' | translate }} in px</mat-label>
-      <input matInput type="number" #magnifierSize="ngModel" min="0"
-             [ngModel]="combinedProperties.magnifierSize"
-             (ngModelChange)="updateModel.emit({
-                  property: 'magnifierSize',
-                  value: $event,
-                  isInputValid: magnifierSize.valid})">
-    </mat-form-field>
-
-    <ng-container *ngIf="combinedProperties.magnifier">
-      {{'propertiesPanel.magnifierZoom' | translate }}
-      <mat-slider min="1" max="3" step="0.1" [ngModel]="combinedProperties.magnifierZoom"
-                  (change)="updateModel.emit({ property: 'magnifierZoom', value: $event.value })">
-      </mat-slider>
-      <div *ngIf="combinedProperties.magnifier">
-        {{combinedProperties.magnifierZoom}}
-      </div>
-    </ng-container>
-  `,
-  styles: [
-  ]
-})
-export class ImagePropertiesComponent {
-  @Input() combinedProperties!: any;
-  @Output() updateModel =
-  new EventEmitter<{ property: string; value: string | number | boolean | null, isInputValid?: boolean | null }>();
-}
diff --git a/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/input-element-properties.component.ts b/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/input-element-properties.component.ts
index aa0616e85263b7a9967ab5e40b8c8f48cef522de..ad5edf1c3e334ff4bf0617595faad15ceeaa69fd 100644
--- a/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/input-element-properties.component.ts
+++ b/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/input-element-properties.component.ts
@@ -1,122 +1,42 @@
-import { Component, EventEmitter, Input, Output } from '@angular/core';
+import {
+  Component, EventEmitter, Input, Output
+} from '@angular/core';
+import { UIElement } from 'common/models/elements/element';
 
 @Component({
   selector: 'aspect-input-element-properties',
   template: `
-    <mat-form-field *ngIf="combinedProperties.appearance !== undefined" appearance="fill">
-      <mat-label>{{'propertiesPanel.appearance' | translate }}</mat-label>
-      <mat-select [value]="combinedProperties.appearance"
-                  (selectionChange)="updateModel.emit({ property: 'appearance', value: $event.value })">
-        <mat-option *ngFor="let option of [{displayValue: 'fill', value: 'fill'},
-                                         {displayValue: 'outline', value: 'outline'}]"
-                    [value]="option.value">
-          {{'propertiesPanel.' + option.displayValue | translate}}
-        </mat-option>
-      </mat-select>
-    </mat-form-field>
-
-    <mat-form-field *ngIf="combinedProperties.minLength !== undefined" appearance="fill">
-      <mat-label>{{'propertiesPanel.minLength' | translate }}</mat-label>
-      <input matInput type="number" #minLength="ngModel" min="0"
-             [ngModel]="combinedProperties.minLength"
-             (ngModelChange)="updateModel.emit({
-                  property: 'minLength',
-                  value: $event,
-                  isInputValid: minLength.valid })">
-    </mat-form-field>
-    <mat-form-field *ngIf="combinedProperties.minLength &&
-                                     $any(combinedProperties.minLength) > 0"
-                    appearance="fill">
-      <mat-label>{{'propertiesPanel.minLengthWarnMessage' | translate }}</mat-label>
-      <input matInput type="text" [value]="$any(combinedProperties.minLengthWarnMessage)"
-             (input)="updateModel.emit({ property: 'minLengthWarnMessage', value: $any($event.target).value })">
-    </mat-form-field>
-
-    <mat-form-field *ngIf="combinedProperties.maxLength !== undefined" appearance="fill">
-      <mat-label>{{'propertiesPanel.maxLength' | translate }}</mat-label>
-      <input matInput type="number" #maxLength="ngModel" min="0"
-             [ngModel]="combinedProperties.maxLength"
-             (ngModelChange)="updateModel.emit({
-                  property: 'maxLength',
-                  value: $event,
-                  isInputValid: maxLength.valid })">
-    </mat-form-field>
-    <mat-form-field *ngIf="combinedProperties.maxLength &&
-                                     $any(combinedProperties.maxLength) > 0"
-                    appearance="fill">
-      <mat-label>{{'propertiesPanel.maxLengthWarnMessage' | translate }}</mat-label>
-      <input matInput type="text" [value]="$any(combinedProperties.maxLengthWarnMessage)"
-             (input)="updateModel.emit({ property: 'maxLengthWarnMessage', value: $any($event.target).value })">
-    </mat-form-field>
-
-    <mat-form-field *ngIf="combinedProperties.pattern !== undefined" appearance="fill">
-      <mat-label>{{'propertiesPanel.pattern' | translate }}</mat-label>
-      <input matInput [value]="$any(combinedProperties.pattern)"
-             (input)="updateModel.emit({ property: 'pattern', value: $any($event.target).value })">
-    </mat-form-field>
-    <mat-form-field *ngIf="combinedProperties.pattern && $any(combinedProperties.pattern) !== ''"
-                    appearance="fill"
-                    matTooltip="Angabe als regulärer Ausdruck.">
-      <mat-label>{{'propertiesPanel.patternWarnMessage' | translate }}</mat-label>
-      <input matInput type="text" [value]="$any(combinedProperties.patternWarnMessage)"
-             (input)="updateModel.emit({ property: 'patternWarnMessage', value: $any($event.target).value })">
-    </mat-form-field>
-
-    <mat-checkbox *ngIf="combinedProperties.clearable !== undefined"
-                  [checked]="$any(combinedProperties.clearable)"
-                  (change)="updateModel.emit({ property: 'clearable', value: $event.checked })">
-      {{'propertiesPanel.clearable' | translate }}
-    </mat-checkbox>
-
-    <mat-form-field *ngIf="combinedProperties.inputAssistancePreset !== undefined" appearance="fill">
-      <mat-label>{{'propertiesPanel.inputAssistance' | translate }}</mat-label>
-      <mat-select [value]="combinedProperties.inputAssistancePreset"
-                  (selectionChange)="updateModel.emit({ property: 'inputAssistancePreset', value: $event.value })">
-        <mat-option *ngFor="let option of [null, 'french', 'numbers', 'numbersAndOperators', 'numbersAndBasicOperators',
-       'comparisonOperators', 'squareDashDot', 'placeValue']"
-                    [value]="option">
-          {{ option === null ? ('propertiesPanel.none' | translate) : ('propertiesPanel.' + option | translate) }}
-        </mat-option>
-      </mat-select>
-    </mat-form-field>
-    <mat-form-field *ngIf="combinedProperties.inputAssistancePreset !== null &&
-                                 combinedProperties.inputAssistancePosition !== undefined"
-                    appearance="fill">
-      <mat-label>{{'propertiesPanel.inputAssistancePosition' | translate }}</mat-label>
-      <mat-select [value]="combinedProperties.inputAssistancePosition"
-                  (selectionChange)="updateModel.emit({ property: 'inputAssistancePosition', value: $event.value })">
-        <mat-option *ngFor="let option of ['floating', 'right']"
-                    [value]="option">
-          {{ 'propertiesPanel.' + option | translate }}
-        </mat-option>
-      </mat-select>
-    </mat-form-field>
-
-    <mat-checkbox *ngIf="combinedProperties.inputAssistancePreset !== null &&
-                       combinedProperties.restrictedToInputAssistanceChars !== undefined"
-                  [checked]="$any(combinedProperties.restrictedToInputAssistanceChars)"
-                  (change)="updateModel.emit({ property: 'restrictedToInputAssistanceChars', value: $event.checked })">
-      {{'propertiesPanel.restrictedToInputAssistanceChars' | translate }}
-    </mat-checkbox>
-
-    <mat-checkbox *ngIf="combinedProperties.showSoftwareKeyboard !== undefined"
-                  [checked]="$any(combinedProperties.showSoftwareKeyboard)"
-                  (change)="updateModel.emit({ property: 'showSoftwareKeyboard', value: $event.checked })">
-      {{'propertiesPanel.showSoftwareKeyboard' | translate }}
-    </mat-checkbox>
-
-    <mat-checkbox *ngIf="combinedProperties.showSoftwareKeyboard"
-                  [checked]="$any(combinedProperties.softwareKeyboardShowFrench)"
-                  (change)="updateModel.emit({ property: 'softwareKeyboardShowFrench', value: $event.checked })">
-      {{'propertiesPanel.softwareKeyboardShowFrench' | translate }}
-    </mat-checkbox>
-  `,
-  styles: [
-    'mat-form-field {width: 100%;}'
-  ]
+    <fieldset *ngIf="combinedProperties.required !== undefined" fxLayout="column">
+      <legend>Eingabeelement</legend>
+      <mat-form-field *ngIf="combinedProperties.label !== undefined" appearance="fill">
+        <mat-label>{{'propertiesPanel.label' | translate }}</mat-label>
+        <input matInput type="text" [value]="$any(combinedProperties.label)"
+               (input)="updateModel.emit({property: 'label', value: $any($event.target).value })">
+      </mat-form-field>
+
+      <mat-checkbox *ngIf="combinedProperties.readOnly !== undefined"
+                    [checked]="$any(combinedProperties.readOnly)"
+                    (change)="updateModel.emit({ property: 'readOnly', value: $event.checked })">
+        {{'propertiesPanel.readOnly' | translate }}
+      </mat-checkbox>
+
+      <mat-checkbox *ngIf="combinedProperties.required !== undefined"
+                    [checked]="$any(combinedProperties.required)"
+                    (change)="updateModel.emit({ property: 'required', value: $event.checked })">
+        {{'propertiesPanel.requiredField' | translate }}
+      </mat-checkbox>
+
+      <mat-form-field appearance="fill">
+        <mat-label>{{'propertiesPanel.requiredWarnMessage' | translate }}</mat-label>
+        <input matInput type="text" [disabled]="!combinedProperties.required"
+               [value]="$any(combinedProperties.requiredWarnMessage)"
+               (input)="updateModel.emit({ property: 'requiredWarnMessage', value: $any($event.target).value })">
+      </mat-form-field>
+    </fieldset>
+  `
 })
 export class InputElementPropertiesComponent {
-  @Input() combinedProperties!: any;
+  @Input() combinedProperties!: UIElement;
   @Output() updateModel =
-  new EventEmitter<{ property: string; value: string | number | boolean | string[], isInputValid?: boolean | null }>();
+    new EventEmitter<{ property: string; value: string | number | boolean | string[], isInputValid?: boolean | null }>();
 }
diff --git a/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/options-field-set.component.ts b/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/options-field-set.component.ts
index c519c472bdd3dbea8f66db5c99470128de36f176..c3a290ba1e1c98576659575ac4f2463f940cf298 100644
--- a/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/options-field-set.component.ts
+++ b/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/options-field-set.component.ts
@@ -1,113 +1,162 @@
 import {
   Component, EventEmitter, Input, Output
 } from '@angular/core';
-import { CdkDragDrop } from '@angular/cdk/drag-drop/drag-events';
+import {
+  TextLabel, TextImageLabel, OptionElement, Label
+} from 'common/models/elements/element';
+import { CombinedProperties } from 'editor/src/app/components/properties-panel/element-properties-panel.component';
+import { LikertRowElement } from 'common/models/elements/compound-elements/likert/likert-row';
+import { IDManager } from 'common/util/id-manager';
+import { UnitService } from 'editor/src/app/services/unit.service';
+import { DialogService } from 'editor/src/app/services/dialog.service';
 import { moveItemInArray } from '@angular/cdk/drag-drop';
-import { DialogService } from '../../../../services/dialog.service';
-import { DomSanitizer } from '@angular/platform-browser';
+import { SelectionService } from 'editor/src/app/services/selection.service';
 
 @Component({
   selector: 'aspect-options-field-set',
   template: `
-    <mat-form-field disabled="true" *ngIf="combinedProperties.options !== undefined">
-      <ng-container>
-        <mat-label>{{'propertiesPanel.options' | translate }}</mat-label>
-        <div class="drop-list" cdkDropList [cdkDropListData]="combinedProperties.options"
-             (cdkDropListDropped)="reorderOptions('options', $any($event))">
-          <div *ngFor="let option of $any(combinedProperties.options); let i = index" cdkDrag
-               fxLayout="row" fxLayoutAlign="end center">
-            <div fxFlex="70">
-              {{option}}
-            </div>
-            <button mat-icon-button color="primary"
-                    (click)="editTextOption('options', i)">
-              <mat-icon>build</mat-icon>
-            </button>
-            <button mat-icon-button color="primary"
-                    (click)="removeOption('options', option)">
-              <mat-icon>clear</mat-icon>
-            </button>
-          </div>
-        </div>
-      </ng-container>
-      <div fxLayout="row" fxLayoutAlign="center center">
-        <button mat-icon-button matPrefix
-                (click)="addOption('options', newOption.value); newOption.select()">
-          <mat-icon>add</mat-icon>
-        </button>
-        <input #newOption matInput type="text" placeholder="Optionstext"
-               (keyup.enter)="addOption('options', newOption.value); newOption.select()">
-      </div>
-    </mat-form-field>
-
-    <mat-form-field disabled="true" *ngIf="combinedProperties.richTextOptions !== undefined">
-      <ng-container>
-        <mat-label>{{'propertiesPanel.options' | translate }}</mat-label>
-        <div class="drop-list" cdkDropList [cdkDropListData]="combinedProperties.richTextOptions"
-             (cdkDropListDropped)="reorderOptions('richTextOptions', $any($event))">
-          <div *ngFor="let option of $any(combinedProperties.richTextOptions); let i = index" cdkDrag
-               fxLayout="row" fxLayoutAlign="end center">
-            <div fxFlex="70" [innerHTML]="sanitizer.bypassSecurityTrustHtml(option)">
-            </div>
-            <button mat-icon-button color="primary"
-                    (click)="editTextOption('richTextOptions', i)">
-              <mat-icon>build</mat-icon>
-            </button>
-            <button mat-icon-button color="primary"
-                    (click)="removeOption('richTextOptions', option)">
-              <mat-icon>clear</mat-icon>
-            </button>
-          </div>
-        </div>
-      </ng-container>
-      <div fxLayout="row" fxLayoutAlign="center center">
-        <button mat-icon-button matPrefix
-                (click)="addOption('richTextOptions', newOption.value); newOption.select()">
-          <mat-icon>add</mat-icon>
-        </button>
-        <input #newOption matInput type="text" placeholder="Optionstext"
-               (keyup.enter)="addOption('richTextOptions', newOption.value); newOption.select()">
-      </div>
-    </mat-form-field>
-  `,
-  styles: [
-    '.mat-form-field {width: 100%;}'
-  ]
+    <!--dropdown-->
+<!--                              [useRichText]="combinedProperties.type === 'radio'"-->
+    <aspect-option-list-panel *ngIf="combinedProperties.options !== undefined"
+                              [title]="'propertiesPanel.options'" [textFieldLabel]="'Neue Option'"
+                              [itemList]="$any(combinedProperties.options)"
+                              (addItem)="addOption('options', $event)"
+                              (removeItem)="removeOption('options', $event)"
+                              (changedItemOrder)="moveOption('options', $event)"
+                              (editItem)="editOption('options', $event)">
+    </aspect-option-list-panel>
+
+    <!--likert-->
+    <aspect-option-list-panel *ngIf="combinedProperties.rows !== undefined"
+                              [itemList]="$any(combinedProperties).rows | LikertRowLabel"
+                              [title]="'rows'"
+                              [textFieldLabel]="'Neue Zeile'"
+
+                              (changedItemOrder)="moveLikertRow($event)"
+
+                              (addItem)="addLikertRow($event)"
+                              (removeItem)="removeLikertRow($event)"
+                              (editItem)="editLikertRow($event)">
+    </aspect-option-list-panel>
+  `
 })
 export class OptionsFieldSetComponent {
-  @Input() combinedProperties!: any;
+  @Input() combinedProperties!: CombinedProperties;
   @Output() updateModel =
-  new EventEmitter<{ property: string; value: string | number | boolean | string[], isInputValid?: boolean | null }>();
+    new EventEmitter<{
+      property: string;
+      value: string | number | boolean | string[] | Label[] | LikertRowElement[]
+    }>();
+
+  constructor(private unitService: UnitService,
+              private selectionService: SelectionService,
+              public dialogService: DialogService) { }
 
-  constructor(public dialogService: DialogService, public sanitizer: DomSanitizer) { }
+  addOption(property: string, option: string): void {
+    const selectedElements = this.selectionService.getSelectedElements() as OptionElement[];
 
-  addOption(property: string, value: string): void {
+    selectedElements.forEach(element => {
+      const newValue = [...this.combinedProperties[property] as Label[], element.getNewOptionLabel(option)];
+      this.unitService.updateElementsProperty([element], property, newValue);
+    });
+  }
+
+  removeOption(property: string, optionIndex: number): void {
+    (this.combinedProperties[property] as Label[]).splice(optionIndex, 1);
     this.updateModel.emit({
       property: property,
-      value: [...(this.combinedProperties[property] as string[]), value]
+      value: this.combinedProperties[property] as Label[]
     });
   }
 
-  removeOption(property: string, option: any): void {
-    const valueList = this.combinedProperties[property] as string[];
-    valueList.splice(valueList.indexOf(option), 1);
-    this.updateModel.emit({ property: property, value: valueList });
+  moveOption(property: string, indices: { previousIndex: number, currentIndex: number }): void {
+    moveItemInArray(this.combinedProperties[property] as Label[],
+      indices.previousIndex,
+      indices.currentIndex);
+    this.updateModel.emit({ property: property, value: this.combinedProperties[property] as Label[] });
+  }
+
+  async editOption(property: string, optionIndex: number): Promise<void> {
+    const selectedOption = (this.combinedProperties[property] as Label[])[optionIndex];
+    await this.dialogService.showLabelEditDialog(selectedOption)
+      .subscribe((result: Label) => {
+        if (result) {
+          (this.combinedProperties[property] as Label[])[optionIndex] = result;
+          this.updateModel.emit({ property, value: (this.combinedProperties[property] as Label[]) });
+        }
+      });
+  }
+
+  notifyListChange(property: string, changedList: TextLabel[]): void {
+    this.updateModel.emit({ property: property, value: changedList });
   }
 
-  async editTextOption(property: string, optionIndex: number): Promise<void> {
-    const oldOptions = this.combinedProperties[property] as string[];
-    await this.dialogService
-      .showRichTextSimpleEditDialog(oldOptions[optionIndex], this.combinedProperties.styling.fontSize)
-      .subscribe((result: string) => {
+  addLikertRow(rowLabelText: string): void {
+    const newRow = new LikertRowElement({
+      type: 'likert-row',
+      rowLabel: {
+        text: rowLabelText,
+        imgSrc: null,
+        imgPosition: 'above'
+      },
+      columnCount: (this.combinedProperties.options as unknown[]).length
+    }, IDManager.getInstance());
+    (this.combinedProperties.rows as LikertRowElement[]).push(newRow);
+    this.updateModel.emit({ property: 'rows', value: this.combinedProperties.rows as LikertRowElement[] });
+  }
+
+  async editLikertRow(rowIndex: number): Promise<void> {
+    const row = (this.combinedProperties.rows as LikertRowElement[])[rowIndex] as LikertRowElement;
+    const columns = this.combinedProperties.options as TextImageLabel[];
+
+    await this.dialogService.showLikertRowEditDialog(row, columns)
+      .subscribe((result: LikertRowElement) => {
         if (result) {
-          oldOptions[optionIndex] = result;
-          this.updateModel.emit({ property, value: oldOptions });
+          if (result.id !== row.id) {
+            this.unitService.updateElementsProperty(
+              [row],
+              'id',
+              result.id
+            );
+          }
+          if (result.rowLabel !== row.rowLabel) {
+            this.unitService.updateElementsProperty([row], 'rowLabel', result.rowLabel);
+          }
+          if (result.value !== row.value) {
+            this.unitService.updateElementsProperty(
+              [row],
+              'value',
+              result.value
+            );
+          }
+          if (result.verticalButtonAlignment !== row.verticalButtonAlignment) {
+            this.unitService.updateElementsProperty(
+              [row],
+              'verticalButtonAlignment',
+              result.verticalButtonAlignment
+            );
+          }
+          if (result.readOnly !== row.readOnly) {
+            this.unitService.updateElementsProperty(
+              [row],
+              'readOnly',
+              result.readOnly
+            );
+          }
         }
       });
   }
 
-  reorderOptions(property: string, event: CdkDragDrop<string[]>): void {
-    moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
-    this.updateModel.emit({ property: property, value: event.container.data });
+  removeLikertRow(index: number): void {
+    const valueList = this.combinedProperties.rows as LikertRowElement[];
+    valueList.splice(index, 1);
+    this.updateModel.emit({ property: 'rows', value: valueList });
+  }
+
+  moveLikertRow(indices: { previousIndex: number, currentIndex: number }): void {
+    moveItemInArray(this.combinedProperties.rows as LikertRowElement[],
+      indices.previousIndex,
+      indices.currentIndex);
+    this.updateModel.emit({ property: 'rows', value: this.combinedProperties.rows as LikertRowElement[] });
   }
 }
diff --git a/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/preset-value-properties.component.ts b/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/preset-value-properties.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0c2461c6a3f6d7027f03092cb9d0c08a0b69e411
--- /dev/null
+++ b/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/preset-value-properties.component.ts
@@ -0,0 +1,42 @@
+import {
+  Component, EventEmitter, Input, Output
+} from '@angular/core';
+import { CombinedProperties } from 'editor/src/app/components/properties-panel/element-properties-panel.component';
+
+@Component({
+  selector: 'aspect-preset-value-properties',
+  template: `
+    <mat-form-field *ngIf="combinedProperties.type === 'text-area'"
+                    class="wide-form-field" appearance="fill">
+      <mat-label>{{'preset' | translate }}</mat-label>
+      <textarea matInput type="text"
+                [value]="$any(combinedProperties.value)"
+                (input)="updateModel.emit({ property: 'value', value: $any($event.target).value })">
+            </textarea>
+    </mat-form-field>
+
+    <mat-form-field *ngIf="combinedProperties.type === 'text-field' || combinedProperties.type === 'text-field-simple'"
+                    class="wide-form-field" appearance="fill">
+      <mat-label>{{'preset' | translate }}</mat-label>
+      <input matInput type="text" [value]="$any(combinedProperties).value"
+             (input)="updateModel.emit({property: 'value', value: $any($event.target).value })">
+    </mat-form-field>
+
+    <mat-form-field *ngIf="combinedProperties.options !== undefined && combinedProperties.rows === undefined"
+                    appearance="fill" class="wide-form-field">
+      <mat-label>{{'preset' | translate }}</mat-label>
+      <mat-select [value]="combinedProperties.value"
+                  (selectionChange)="updateModel.emit({ property: 'value', value: $event.value })">
+        <mat-option [value]="null">{{'propertiesPanel.undefined' | translate }}</mat-option>
+        <mat-option *ngFor="let option of $any(combinedProperties.options); let i = index" [value]="i">
+          <div fxFlex fxFlexAlign="center" [innerHTML]="option.text + ' (Index: ' + i + ')'"></div>
+        </mat-option>
+      </mat-select>
+    </mat-form-field>
+  `
+})
+export class PresetValuePropertiesComponent {
+  @Input() combinedProperties!: CombinedProperties;
+  @Output() updateModel =
+    new EventEmitter<{ property: string; value: string | number | boolean | string[], isInputValid?: boolean | null }>();
+}
diff --git a/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/scale-and-zoom-properties.component.ts b/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/scale-and-zoom-properties.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6d44b9535b8b60cba1ecb8efb4c1f3deee60c8c3
--- /dev/null
+++ b/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/scale-and-zoom-properties.component.ts
@@ -0,0 +1,55 @@
+import {
+  Component, EventEmitter, Input, Output
+} from '@angular/core';
+import { UIElement } from 'common/models/elements/element';
+
+@Component({
+  selector: 'aspect-scale-and-zoom-properties',
+  template: `
+    <div fxLayout="column" fxLayoutGap="5px">
+      <mat-checkbox *ngIf="combinedProperties.scale !== undefined"
+                    [checked]="$any(combinedProperties.scale)"
+                    (change)="updateModel.emit({ property: 'scale', value: $event.checked })">
+        {{'propertiesPanel.scale' | translate }}
+      </mat-checkbox>
+
+      <mat-checkbox *ngIf="combinedProperties.magnifier !== undefined"
+                    [checked]="$any(combinedProperties.magnifier)"
+                    (change)="updateModel.emit({ property: 'magnifier', value: $event.checked })">
+        {{'propertiesPanel.magnifier' | translate }}
+      </mat-checkbox>
+
+      <mat-form-field appearance="fill" *ngIf="combinedProperties.magnifierSize !== undefined">
+        <mat-label>{{'propertiesPanel.magnifierSize' | translate }} in px</mat-label>
+        <input matInput type="number" #magnifierSize="ngModel" min="0"
+               [disabled]="!combinedProperties.magnifier"
+               [ngModel]="combinedProperties.magnifierSize"
+               (ngModelChange)="updateModel.emit({
+                    property: 'magnifierSize',
+                    value: $event,
+                    isInputValid: magnifierSize.valid})">
+      </mat-form-field>
+
+      <div *ngIf="combinedProperties.magnifierZoom !== undefined"
+           [class.disabled-label]="!combinedProperties.magnifier">
+        {{'propertiesPanel.magnifierZoom' | translate }}
+      </div>
+      <mat-slider *ngIf="combinedProperties.magnifierZoom !== undefined"
+                  min="1" max="3" step="0.1" [disabled]="!combinedProperties.magnifier"
+                  [ngModel]="combinedProperties.magnifierZoom"
+                  (change)="updateModel.emit({ property: 'magnifierZoom', value: $event.value })">
+      </mat-slider>
+      <div *ngIf="combinedProperties.magnifier">
+        {{combinedProperties.magnifierZoom}}
+      </div>
+    </div>
+  `,
+  styles: [
+    '.disabled-label {color: rgba(0, 0, 0, 0.26)}'
+  ]
+})
+export class ScaleAndZoomPropertiesComponent {
+  @Input() combinedProperties!: UIElement;
+  @Output() updateModel =
+    new EventEmitter<{ property: string; value: string | number | boolean | null, isInputValid?: boolean | null }>();
+}
diff --git a/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/select-properties.component.ts b/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/select-properties.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3e642370374a18cf0100d45a92d3ab6cff1c37a9
--- /dev/null
+++ b/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/select-properties.component.ts
@@ -0,0 +1,62 @@
+import {
+  Component, EventEmitter, Input, Output
+} from '@angular/core';
+import { CombinedProperties } from 'editor/src/app/components/properties-panel/element-properties-panel.component';
+import { MatCheckboxChange } from '@angular/material/checkbox';
+
+@Component({
+  selector: 'aspect-select-properties',
+  template: `
+    <mat-checkbox *ngIf="combinedProperties.strikeOtherOptions !== undefined"
+                  [checked]="$any(combinedProperties.strikeOtherOptions)"
+                  (change)="updateModel.emit({ property: 'strikeOtherOptions', value: $event.checked })">
+      {{'propertiesPanel.strikeOtherOptions' | translate }}
+    </mat-checkbox>
+    <mat-checkbox *ngIf="combinedProperties.strikeSelectedOption !== undefined"
+                  [checked]="$any(combinedProperties.strikeSelectedOption)"
+                  (change)="updateModel.emit({ property: 'strikeSelectedOption', value: $event.checked })">
+      {{'propertiesPanel.strikeSelectedOption' | translate }}
+    </mat-checkbox>
+    <mat-checkbox *ngIf="combinedProperties.allowUnset !== undefined"
+                  [checked]="$any(combinedProperties.allowUnset)"
+                  (change)="updateModel.emit({ property: 'allowUnset', value: $event.checked })">
+      {{'propertiesPanel.allowUnset' | translate }}
+    </mat-checkbox>
+
+    <mat-checkbox *ngIf="combinedProperties.itemsPerRow !== undefined"
+                  (change)="setItemsPerRow($event)"
+                  [checked]="$any(combinedProperties.itemsPerRow)">
+      {{'limitItemPerRow' | translate}}
+    </mat-checkbox>
+
+    <mat-form-field *ngIf="combinedProperties.itemsPerRow !== undefined"
+                    appearance="fill" class="mdInput textsingleline">
+      <mat-label>{{'itemsPerRow' | translate }}</mat-label>
+      <input matInput type="number" [min]="1" [pattern]="'[1-9]'" #itemsPerRow="ngModel" required
+             [disabled]="!isItemsPerRowSet"
+             [ngModel]="$any(combinedProperties.itemsPerRow)"
+             (input)="itemsPerRow.valid &&
+                      updateModel.emit({ property: 'itemsPerRow', value: $any($event.target).value })">
+      <mat-error *ngIf="itemsPerRow.errors?.['pattern']">
+        {{'numberGreater0' | translate}}
+      </mat-error>
+    </mat-form-field>
+  `
+})
+export class SelectPropertiesComponent {
+  @Input() combinedProperties!: CombinedProperties;
+  @Output() updateModel =
+    new EventEmitter<{
+      property: string,
+      value: string | number | boolean | string[] | null
+    }>();
+
+  isItemsPerRowSet = false;
+
+  setItemsPerRow(event: MatCheckboxChange) {
+    this.isItemsPerRowSet = event.checked;
+    if (!event.checked) {
+      this.updateModel.emit({ property: 'itemsPerRow', value: null });
+    }
+  }
+}
diff --git a/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/slider-properties.component.ts b/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/slider-properties.component.ts
index d53f8639404b9976c8e02e311e1b74c8cbda9e4b..444793379d5f3aafd189668df2dd74c2aef393c7 100644
--- a/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/slider-properties.component.ts
+++ b/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/slider-properties.component.ts
@@ -1,4 +1,6 @@
-import { Component, EventEmitter, Input, Output } from '@angular/core';
+import {
+  Component, EventEmitter, Input, Output
+} from '@angular/core';
 
 @Component({
   selector: 'aspect-slider-properties',
@@ -36,12 +38,10 @@ import { Component, EventEmitter, Input, Output } from '@angular/core';
                   (change)="updateModel.emit({ property: 'thumbLabel', value: $event.checked })">
       {{'propertiesPanel.thumbLabel' | translate }}
     </mat-checkbox>
-  `,
-  styles: [
-  ]
+  `
 })
 export class SliderPropertiesComponent {
   @Input() combinedProperties!: any;
   @Output() updateModel =
-  new EventEmitter<{ property: string; value: string | number | boolean | string[], isInputValid?: boolean | null }>();
+    new EventEmitter<{ property: string; value: string | number | boolean | string[], isInputValid?: boolean | null }>();
 }
diff --git a/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/text-field-element-properties.component.ts b/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/text-field-element-properties.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d50060ab72b6a6f13fb21073b7426107f353e4d8
--- /dev/null
+++ b/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/text-field-element-properties.component.ts
@@ -0,0 +1,128 @@
+import { Component, EventEmitter, Input, Output } from '@angular/core';
+import { CombinedProperties } from 'editor/src/app/components/properties-panel/element-properties-panel.component';
+
+@Component({
+  selector: 'aspect-text-field-element-properties',
+  template: `
+    <mat-form-field *ngIf="combinedProperties.appearance !== undefined" appearance="fill">
+      <mat-label>{{'propertiesPanel.appearance' | translate }}</mat-label>
+      <mat-select [value]="combinedProperties.appearance"
+                  (selectionChange)="updateModel.emit({ property: 'appearance', value: $event.value })">
+        <mat-option *ngFor="let option of [{displayValue: 'fill', value: 'fill'},
+                                         {displayValue: 'outline', value: 'outline'}]"
+                    [value]="option.value">
+          {{'propertiesPanel.' + option.displayValue | translate}}
+        </mat-option>
+      </mat-select>
+    </mat-form-field>
+
+    <ng-container *ngIf="combinedProperties.minLength !== undefined">
+      <mat-form-field class="wide-form-field" appearance="fill">
+        <mat-label>{{'propertiesPanel.minLength' | translate }}</mat-label>
+        <input matInput type="number" #minLength="ngModel" min="0"
+               [ngModel]="combinedProperties.minLength"
+               (ngModelChange)="updateModel.emit({
+                    property: 'minLength',
+                    value: $event,
+                    isInputValid: minLength.valid })">
+      </mat-form-field>
+      <mat-form-field class="wide-form-field" appearance="fill">
+        <mat-label>{{'propertiesPanel.minLengthWarnMessage' | translate }}</mat-label>
+        <input matInput type="text"
+               [disabled]="!combinedProperties.minLength"
+               [value]="$any(combinedProperties.minLengthWarnMessage)"
+               (input)="updateModel.emit({ property: 'minLengthWarnMessage', value: $any($event.target).value })">
+      </mat-form-field>
+    </ng-container>
+
+    <ng-container *ngIf="combinedProperties.maxLength !== undefined">
+      <mat-form-field class="wide-form-field" appearance="fill">
+        <mat-label>{{'propertiesPanel.maxLength' | translate }}</mat-label>
+        <input matInput type="number" #maxLength="ngModel" min="0"
+               [ngModel]="combinedProperties.maxLength"
+               (ngModelChange)="updateModel.emit({
+                    property: 'maxLength',
+                    value: $event,
+                    isInputValid: maxLength.valid })">
+      </mat-form-field>
+      <mat-form-field class="wide-form-field" appearance="fill">
+        <mat-label>{{'propertiesPanel.maxLengthWarnMessage' | translate }}</mat-label>
+        <input matInput type="text"
+               [disabled]="!combinedProperties.maxLength"
+               [value]="$any(combinedProperties.maxLengthWarnMessage)"
+               (input)="updateModel.emit({ property: 'maxLengthWarnMessage', value: $any($event.target).value })">
+      </mat-form-field>
+    </ng-container>
+
+    <ng-container *ngIf="combinedProperties.pattern !== undefined">
+      <mat-form-field class="wide-form-field" appearance="fill"
+                      matTooltip="Angabe als regulärer Ausdruck.">
+        <mat-label>{{'propertiesPanel.pattern' | translate }}</mat-label>
+        <input matInput [value]="$any(combinedProperties.pattern)"
+               (input)="updateModel.emit({ property: 'pattern', value: $any($event.target).value })">
+      </mat-form-field>
+      <mat-form-field class="wide-form-field" appearance="fill">
+        <mat-label>{{'propertiesPanel.patternWarnMessage' | translate }}</mat-label>
+        <input matInput type="text"
+               [disabled]="!combinedProperties.pattern"
+               [value]="$any(combinedProperties.patternWarnMessage)"
+               (input)="updateModel.emit({ property: 'patternWarnMessage', value: $any($event.target).value })">
+      </mat-form-field>
+    </ng-container>
+
+    <mat-checkbox *ngIf="combinedProperties.clearable !== undefined"
+                  [checked]="$any(combinedProperties.clearable)"
+                  (change)="updateModel.emit({ property: 'clearable', value: $event.checked })">
+      {{'propertiesPanel.clearable' | translate }}
+    </mat-checkbox>
+
+    <mat-checkbox *ngIf="combinedProperties.showSoftwareKeyboard !== undefined"
+                  [checked]="$any(combinedProperties.showSoftwareKeyboard)"
+                  (change)="updateModel.emit({ property: 'showSoftwareKeyboard', value: $event.checked })">
+      {{'propertiesPanel.showSoftwareKeyboard' | translate }}
+    </mat-checkbox>
+    <mat-checkbox *ngIf="combinedProperties.showSoftwareKeyboard !== undefined"
+                  [disabled]="!combinedProperties.showSoftwareKeyboard"
+                  [checked]="$any(combinedProperties.softwareKeyboardShowFrench)"
+                  (change)="updateModel.emit({ property: 'softwareKeyboardShowFrench', value: $event.checked })">
+      {{'propertiesPanel.softwareKeyboardShowFrench' | translate }}
+    </mat-checkbox>
+
+    <mat-form-field *ngIf="combinedProperties.inputAssistancePreset !== undefined" appearance="fill"
+                    class="wide-form-field">
+      <mat-label>{{'propertiesPanel.inputAssistance' | translate }}</mat-label>
+      <mat-select [value]="combinedProperties.inputAssistancePreset"
+                  (selectionChange)="updateModel.emit({ property: 'inputAssistancePreset', value: $event.value })">
+        <mat-option *ngFor="let option of [null, 'french', 'numbers', 'numbersAndOperators', 'numbersAndBasicOperators',
+       'comparisonOperators', 'squareDashDot', 'placeValue']"
+                    [value]="option">
+          {{ option === null ? ('propertiesPanel.none' | translate) : ('propertiesPanel.' + option | translate) }}
+        </mat-option>
+      </mat-select>
+    </mat-form-field>
+    <mat-form-field *ngIf="combinedProperties.inputAssistancePreset !== null &&
+                           combinedProperties.inputAssistancePosition !== undefined"
+                    appearance="fill">
+      <mat-label>{{'propertiesPanel.inputAssistancePosition' | translate }}</mat-label>
+      <mat-select [value]="combinedProperties.inputAssistancePosition"
+                  (selectionChange)="updateModel.emit({ property: 'inputAssistancePosition', value: $event.value })">
+        <mat-option *ngFor="let option of ['floating', 'right']"
+                    [value]="option">
+          {{ 'propertiesPanel.' + option | translate }}
+        </mat-option>
+      </mat-select>
+    </mat-form-field>
+
+    <mat-checkbox *ngIf="combinedProperties.inputAssistancePreset !== null &&
+                       combinedProperties.restrictedToInputAssistanceChars !== undefined"
+                  [checked]="$any(combinedProperties.restrictedToInputAssistanceChars)"
+                  (change)="updateModel.emit({ property: 'restrictedToInputAssistanceChars', value: $event.checked })">
+      {{'propertiesPanel.restrictedToInputAssistanceChars' | translate }}
+    </mat-checkbox>
+  `
+})
+export class TextFieldElementPropertiesComponent {
+  @Input() combinedProperties!: CombinedProperties;
+  @Output() updateModel =
+    new EventEmitter<{ property: string; value: string | number | boolean | string[], isInputValid?: boolean | null }>();
+}
diff --git a/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/text-properties-field-set.component.ts b/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/text-properties-field-set.component.ts
index 8b6b3022ce3d624979a5431f0fdb233b3d5dec96..27bd9d6d601687c8545eff6e3bf19ac052bd0e31 100644
--- a/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/text-properties-field-set.component.ts
+++ b/projects/editor/src/app/components/properties-panel/model-properties-tab/input-groups/text-properties-field-set.component.ts
@@ -1,15 +1,14 @@
 import {
   Component, EventEmitter, Input, Output
 } from '@angular/core';
+import { TextElement } from 'common/models/elements/text/text';
 import { DialogService } from '../../../../services/dialog.service';
 import { SelectionService } from '../../../../services/selection.service';
-import { TextElement } from 'common/models/elements/text/text';
 
 @Component({
   selector: 'aspect-text-properties-field-set',
   template: `
-    <fieldset *ngIf="combinedProperties.text">
-      <legend>Textelement</legend>
+    <div *ngIf="combinedProperties.text" fxLayout="column">
       <ng-container>
         <div class="text-text"
              [innerHTML]="$any(combinedProperties.text) | safeResourceHTML"
@@ -41,24 +40,17 @@ import { TextElement } from 'common/models/elements/text/text';
                     (change)="updateModel.emit({ property: 'highlightableOrange', value: $event.checked })">
         {{'propertiesPanel.highlightableOrange' | translate }}
       </mat-checkbox>
-    </fieldset>
+    </div>
   `,
   styles: [
-    'mat-checkbox {margin-left: 15px;}',
-    '.text-text {min-height: 125px; max-height: 500px; overflow: auto; margin-bottom: 10px;}',
-    '.text-text {background-color: rgba(0,0,0,.04); cursor: pointer;}',
-    '::ng-deep .text-text p:empty::after {content: "\\00A0";}',
-    '::ng-deep .text-text h1 {font-weight: bold; font-size: 20px;}',
-    '::ng-deep .text-text h2 {font-weight: bold; font-size: 18px;}',
-    '::ng-deep .text-text h3 {font-weight: bold; font-size: 16px;}',
-    '::ng-deep .text-text h4 {font-weight: normal; font-size: 16px;}',
-    '::ng-deep .text-text mark {color: inherit;}'
+    '.text-text {min-height: 125px; max-height: 400px; overflow: auto;}',
+    '.text-text {background-color: rgba(0,0,0,.04); cursor: pointer; margin-bottom: 10px;}'
   ]
 })
 export class TextPropertiesFieldSetComponent {
   @Input() combinedProperties!: any;
   @Output() updateModel =
-  new EventEmitter<{ property: string; value: string | number | boolean | string[], isInputValid?: boolean | null }>();
+    new EventEmitter<{ property: string; value: string | number | boolean | string[], isInputValid?: boolean | null }>();
 
   constructor(public dialogService: DialogService, public selectionService: SelectionService) {}
 
diff --git a/projects/editor/src/app/components/properties-panel/option-list-panel.component.ts b/projects/editor/src/app/components/properties-panel/option-list-panel.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ef3e289c484333f7c5fd7019c0dd9fda7a7e6996
--- /dev/null
+++ b/projects/editor/src/app/components/properties-panel/option-list-panel.component.ts
@@ -0,0 +1,62 @@
+import {
+  Component, EventEmitter, Input, Output
+} from '@angular/core';
+import { CdkDragDrop } from '@angular/cdk/drag-drop/drag-events';
+import { Label } from 'common/models/elements/element';
+
+@Component({
+  selector: 'aspect-option-list-panel',
+  template: `
+    <fieldset fxLayout="column">
+      <legend>{{title | translate }}</legend>
+      <mat-form-field appearance="outline">
+        <mat-label>{{textFieldLabel}}</mat-label>
+        <input #newItem matInput type="text" placeholder="Fragetext"
+               (keyup.enter)="addListItem(newItem.value); newItem.select()">
+        <button mat-mini-fab matSuffix color="primary" [style.bottom.px]="3"
+                (click)="addListItem(newItem.value); newItem.select()">
+          <mat-icon>add</mat-icon>
+        </button>
+      </mat-form-field>
+
+      <div class="drop-list" cdkDropList [cdkDropListData]="itemList"
+           (cdkDropListDropped)="moveListValue($event)">
+        <div *ngFor="let item of itemList; let i = index" cdkDrag
+             class="option-draggable" fxLayout="row">
+          <div fxFlex fxFlexAlign="center" [innerHTML]="item.text"></div>
+          <img [src]="$any(item).imgSrc"
+               [style.object-fit]="'scale-down'" [style.height.px]="40">
+          <button mat-icon-button color="primary"
+                  (click)="editItem.emit(i)">
+            <mat-icon>build</mat-icon>
+          </button>
+          <button mat-icon-button color="primary"
+                  (click)="removeListItem(i)">
+            <mat-icon>clear</mat-icon>
+          </button>
+        </div>
+      </div>
+    </fieldset>
+  `
+})
+export class OptionListPanelComponent {
+  @Input() title!: string;
+  @Input() textFieldLabel!: string;
+  @Input() itemList!: Label[];
+  @Output() addItem = new EventEmitter<string>();
+  @Output() removeItem = new EventEmitter<number>();
+  @Output() editItem = new EventEmitter<number>();
+  @Output() changedItemOrder = new EventEmitter<{ previousIndex: number, currentIndex: number }>();
+
+  addListItem(text: string): void {
+    this.addItem.emit(text);
+  }
+
+  removeListItem(itemIndex: number): void {
+    this.removeItem.emit(itemIndex);
+  }
+
+  moveListValue(event: CdkDragDrop<Label[]>): void {
+    this.changedItemOrder.emit({ previousIndex: event.previousIndex, currentIndex: event.currentIndex });
+  }
+}
diff --git a/projects/editor/src/app/components/properties-panel/position-properties-tab/element-position-properties.component.ts b/projects/editor/src/app/components/properties-panel/position-properties-tab/element-position-properties.component.ts
index 88aedbbdd7eacbc07dd678ab91c8b13cd8d5fca1..045cbe78688b290e6e2c956c6fcfe74007f5c3ac 100644
--- a/projects/editor/src/app/components/properties-panel/position-properties-tab/element-position-properties.component.ts
+++ b/projects/editor/src/app/components/properties-panel/position-properties-tab/element-position-properties.component.ts
@@ -1,9 +1,9 @@
 import {
   Component, Input
 } from '@angular/core';
+import { PositionedUIElement, PositionProperties } from 'common/models/elements/element';
 import { UnitService } from '../../../services/unit.service';
 import { SelectionService } from '../../../services/selection.service';
-import { PositionedUIElement, PositionProperties } from 'common/models/elements/element';
 
 @Component({
   selector: 'aspect-element-postion-properties',
@@ -39,14 +39,10 @@ import { PositionedUIElement, PositionProperties } from 'common/models/elements/
         </div>
       </ng-container>
     </div>
-  `,
-  styles: [
-    'aspect-position-field-set {margin-bottom: 20px;}',
-    ':host ::ng-deep fieldset {padding-bottom: 0;}'
-  ]
+  `
 })
 export class ElementPositionPropertiesComponent {
-  @Input() dimensions!: { width: number; height: number; dynamicWidth: boolean; };
+  @Input() dimensions!: { width?: number; height?: number; dynamicWidth: boolean; };
   @Input() positionProperties: PositionProperties | undefined;
 
   constructor(public unitService: UnitService, public selectionService: SelectionService) { }
diff --git a/projects/editor/src/app/components/properties-panel/position-properties-tab/input-groups/dimension-field-set.component.ts b/projects/editor/src/app/components/properties-panel/position-properties-tab/input-groups/dimension-field-set.component.ts
index de37bc75777aa0ce60f9eefdedd497090a129d11..cfe65d38df4f4d7744c7a9bf1c5241262098d15e 100644
--- a/projects/editor/src/app/components/properties-panel/position-properties-tab/input-groups/dimension-field-set.component.ts
+++ b/projects/editor/src/app/components/properties-panel/position-properties-tab/input-groups/dimension-field-set.component.ts
@@ -1,6 +1,4 @@
-import {
-  Component, EventEmitter, Input, Output
-} from '@angular/core';
+import { Component, Input } from '@angular/core';
 import { PositionProperties } from 'common/models/elements/element';
 import { UnitService } from 'editor/src/app/services/unit.service';
 import { SelectionService } from 'editor/src/app/services/selection.service';
@@ -31,7 +29,7 @@ import { SelectionService } from 'editor/src/app/services/selection.service';
                           (positionProperties?.dynamicPositioning && positionProperties?.fixedSize)">
           {{'propertiesPanel.width' | translate }}
         </mat-label>
-        <input matInput type="number" #width="ngModel" min="0"
+        <input matInput type="number" min="0"
                [disabled]="$any(dimensions.dynamicWidth)"
                [ngModel]="dimensions.width"
                (ngModelChange)="updateDimensionProperty('width', $event)">
@@ -54,19 +52,16 @@ import { SelectionService } from 'editor/src/app/services/selection.service';
                           (positionProperties?.fixedSize || positionProperties?.useMinHeight))">
           {{'propertiesPanel.height' | translate }}
         </mat-label>
-        <input matInput type="number" #height="ngModel" min="0"
+        <input matInput type="number" min="0"
                [ngModel]="dimensions.height"
                (ngModelChange)="updateDimensionProperty('height', $event)">
       </mat-form-field>
     </fieldset>
-  `,
-  styles: [
-    '.mat-form-field {display: inline;}'
-  ]
+  `
 })
 export class DimensionFieldSetComponent {
   @Input() positionProperties: PositionProperties | undefined;
-  @Input() dimensions!: { width: number; height: number; dynamicWidth?: boolean };
+  @Input() dimensions!: { width?: number; height?: number; dynamicWidth?: boolean };
 
   constructor(public unitService: UnitService, public selectionService: SelectionService) { }
 
diff --git a/projects/editor/src/app/components/properties-panel/position-properties-tab/input-groups/position-field-set.component.ts b/projects/editor/src/app/components/properties-panel/position-properties-tab/input-groups/position-field-set.component.ts
index 04dcee575a01cbddf9023103ac43f25fef14c673..011de1f564fbcb882e3fadc6caa46b5b2bfa0495 100644
--- a/projects/editor/src/app/components/properties-panel/position-properties-tab/input-groups/position-field-set.component.ts
+++ b/projects/editor/src/app/components/properties-panel/position-properties-tab/input-groups/position-field-set.component.ts
@@ -8,9 +8,11 @@ import { PositionProperties } from 'common/models/elements/element';
   template: `
     <fieldset>
       <legend>Position</legend>
-      <ng-container *ngIf="!positionProperties.dynamicPositioning; else elseBlock">
+      <div *ngIf="!positionProperties.dynamicPositioning; else elseBlock"
+           fxLayout="row" fxLayoutGap="10px">
         <mat-form-field *ngIf="!positionProperties.dynamicPositioning &&
-                               positionProperties.xPosition !== undefined" appearance="fill">
+                               positionProperties.xPosition !== undefined"
+                        fxFlex>
           <mat-label>{{'propertiesPanel.xPosition' | translate }}</mat-label>
           <input matInput type="number" #xPosition="ngModel" min="0"
                  [ngModel]="positionProperties.xPosition"
@@ -18,36 +20,38 @@ import { PositionProperties } from 'common/models/elements/element';
                         { property: 'xPosition', value: $event, isInputValid: xPosition.valid && $event !== null })">
         </mat-form-field>
         <mat-form-field *ngIf="!positionProperties.dynamicPositioning &&
-                                 positionProperties.yPosition !== undefined" appearance="fill">
+                                 positionProperties.yPosition !== undefined"
+                        fxFlex>
           <mat-label>{{'propertiesPanel.yPosition' | translate }}</mat-label>
           <input matInput type="number" #yPosition="ngModel" min="0"
                  [ngModel]="positionProperties.yPosition"
                  (ngModelChange)="updateModel.emit(
                         { property: 'yPosition', value: $event, isInputValid: yPosition.valid && $event !== null })">
         </mat-form-field>
-      </ng-container>
+      </div>
 
       <ng-template #elseBlock>
         {{'propertiesPanel.grid' | translate }}
-        <div class="input-group">
-          <mat-form-field>
-            <mat-label>{{'propertiesPanel.column' | translate }}</mat-label>
+        <div fxLayout="row" fxLayoutGap="10px">
+          <mat-form-field fxFlex>
+            <mat-label>{{'column' | translate }}</mat-label>
             <input matInput type="number" [ngModel]="positionProperties.gridColumn"
                    (ngModelChange)="updateModel.emit({ property: 'gridColumn', value: $event })">
           </mat-form-field>
-          <mat-form-field>
-            <mat-label>{{'propertiesPanel.row' | translate }}</mat-label>
-            <input matInput type="number" [ngModel]="positionProperties.gridRow"
-                   (ngModelChange)="updateModel.emit({ property: 'gridRow', value: $event })">
-          </mat-form-field>
-
-          <mat-form-field>
+          <mat-form-field fxFlex="40">
             <mat-label>{{'propertiesPanel.columnRange' | translate }}</mat-label>
             <input matInput type="number"
                    [ngModel]="positionProperties.gridColumnRange"
                    (ngModelChange)="updateModel.emit({ property: 'gridColumnRange', value: $event })">
           </mat-form-field>
-          <mat-form-field>
+        </div>
+        <div fxLayout="row" fxLayoutGap="10px">
+          <mat-form-field fxFlex>
+            <mat-label>{{'row' | translate }}</mat-label>
+            <input matInput type="number" [ngModel]="positionProperties.gridRow"
+                   (ngModelChange)="updateModel.emit({ property: 'gridRow', value: $event })">
+          </mat-form-field>
+          <mat-form-field fxFlex="40">
             <mat-label>{{'propertiesPanel.rowRange' | translate }}</mat-label>
             <input matInput type="number"
                    [ngModel]="positionProperties.gridRowRange"
@@ -56,16 +60,16 @@ import { PositionProperties } from 'common/models/elements/element';
         </div>
 
         {{'propertiesPanel.margin' | translate }}
-        <div class="input-group">
-          <mat-form-field class="centered-form-field small-input">
+        <div fxLayout="column" class="margin-controls">
+          <mat-form-field fxFlexAlign="center">
             <mat-label>{{'propertiesPanel.top' | translate }}</mat-label>
             <input matInput type="number" #marginTop="ngModel"
                    [ngModel]="positionProperties.marginTop"
                    (ngModelChange)="updateModel.emit(
                           { property: 'marginTop', value: $event, isInputValid: marginTop.valid && $event !== null })">
           </mat-form-field>
-          <div fxLayoutAlign="row">
-            <mat-form-field class="small-input">
+          <div fxLayout="row" fxLayoutAlign="space-around center">
+            <mat-form-field>
               <mat-label>{{'propertiesPanel.left' | translate }}</mat-label>
               <input matInput type="number" #marginLeft="ngModel"
                      [ngModel]="positionProperties.marginLeft"
@@ -75,7 +79,7 @@ import { PositionProperties } from 'common/models/elements/element';
                        isInputValid: marginLeft.valid && $event !== null
                      })">
             </mat-form-field>
-            <mat-form-field class="right-form-field small-input">
+            <mat-form-field>
               <mat-label>{{'propertiesPanel.right' | translate }}</mat-label>
               <input matInput type="number" #marginRight="ngModel"
                      [ngModel]="positionProperties.marginRight"
@@ -85,7 +89,7 @@ import { PositionProperties } from 'common/models/elements/element';
                               isInputValid: marginRight .valid && $event !== null })">
             </mat-form-field>
           </div>
-          <mat-form-field class="centered-form-field small-input">
+          <mat-form-field fxFlexAlign="center">
             <mat-label>{{'propertiesPanel.bottom' | translate }}</mat-label>
             <input matInput type="number" #marginBottom="ngModel"
                    [ngModel]="positionProperties.marginBottom"
@@ -110,12 +114,9 @@ import { PositionProperties } from 'common/models/elements/element';
     </fieldset>
   `,
   styles: [
-    '.centered-form-field {margin-left: 25%;}',
-    '.right-form-field {margin-left: 15px;}',
-    '.input-group {background-color: rgba(0,0,0,.04); margin-bottom: 10px;}',
-    '.mat-form-field {display: inline;}',
-    '.small-input {display: inline-block;}',
-    '::ng-deep aspect-position-field-set .small-input .mat-form-field-infix {width: 100px; margin: 0 5px;}'
+    '.margin-controls mat-form-field {width: 100px;}',
+    '.margin-controls {margin-bottom: 10px;}',
+    'mat-form-field {width: 110px;}'
   ]
 })
 export class PositionFieldSetComponent {
diff --git a/projects/editor/src/app/components/properties-panel/style-properties-tab/element-style-properties.component.ts b/projects/editor/src/app/components/properties-panel/style-properties-tab/element-style-properties.component.ts
index 27daacccc22347d200e3fd909a310e713b5ab72b..a88f7c86e04fb39011e64c528d17c2606dbfaccb 100644
--- a/projects/editor/src/app/components/properties-panel/style-properties-tab/element-style-properties.component.ts
+++ b/projects/editor/src/app/components/properties-panel/style-properties-tab/element-style-properties.component.ts
@@ -1,13 +1,11 @@
-import {
-  Component, EventEmitter, Input, Output
-} from '@angular/core';
+import { Component, Input } from '@angular/core';
 import { BasicStyles, ExtendedStyles } from 'common/models/elements/element';
 import { UnitService } from 'editor/src/app/services/unit.service';
 
 @Component({
   selector: 'aspect-element-style-properties',
   template: `
-    <div fxLayout="column">
+    <div fxLayout="column" *ngIf="styles">
       <mat-checkbox *ngIf="styles.lineColoring !== undefined"
                     [checked]="$any(styles.lineColoring)"
                     (change)="unitService.updateSelectedElementsStyleProperty('lineColoring', $event.checked)">
@@ -39,12 +37,6 @@ import { UnitService } from 'editor/src/app/services/unit.service';
              [value]="styles.selectionColor"
              (input)="unitService.updateSelectedElementsStyleProperty('selectionColor', $any($event.target).value)">
 
-      <mat-form-field *ngIf="styles.borderRadius !== undefined" appearance="fill">
-        <mat-label>{{'propertiesPanel.borderRadius' | translate }}</mat-label>
-        <input matInput type="number" [ngModel]="styles.borderRadius"
-               (input)="unitService.updateSelectedElementsStyleProperty('borderRadius', $any($event.target).value)">
-      </mat-form-field>
-
       <mat-form-field *ngIf="styles.itemBackgroundColor !== undefined"
                       appearance="fill" class="mdInput textsingleline">
         <mat-label>{{'propertiesPanel.itemBackgroundColor' | translate }}</mat-label>
@@ -71,19 +63,6 @@ import { UnitService } from 'editor/src/app/services/unit.service';
              [value]="styles.backgroundColor"
              (input)="unitService.updateSelectedElementsStyleProperty('backgroundColor', $any($event.target).value)">
 
-      <mat-form-field *ngIf="styles.borderColor !== undefined"
-                      appearance="fill" class="mdInput textsingleline">
-        <mat-label>{{'propertiesPanel.borderColor' | translate }}</mat-label>
-        <input matInput type="text" [value]="styles.borderColor"
-               (input)="unitService.updateSelectedElementsStyleProperty('borderColor', $any($event.target).value)">
-        <button mat-icon-button matSuffix (click)="borderColorInput.click()">
-          <mat-icon>edit</mat-icon>
-        </button>
-      </mat-form-field>
-      <input matInput type="color" hidden #borderColorInput
-             [value]="styles.borderColor"
-             (input)="unitService.updateSelectedElementsStyleProperty('borderColor', $any($event.target).value)">
-
       <mat-form-field *ngIf="styles.fontColor !== undefined"
                       appearance="fill" class="mdInput textsingleline">
         <mat-label>{{'propertiesPanel.fontColor' | translate }}</mat-label>
@@ -134,6 +113,30 @@ import { UnitService } from 'editor/src/app/services/unit.service';
         {{'propertiesPanel.underline' | translate }}
       </mat-checkbox>
 
+    </div>
+
+    <fieldset *ngIf="styles && styles.borderRadius !== undefined">
+      <legend>Rahmen</legend>
+
+      <mat-form-field *ngIf="styles.borderRadius !== undefined" appearance="fill">
+        <mat-label>{{'propertiesPanel.borderRadius' | translate }}</mat-label>
+        <input matInput type="number" [ngModel]="styles.borderRadius"
+               (input)="unitService.updateSelectedElementsStyleProperty('borderRadius', $any($event.target).value)">
+      </mat-form-field>
+
+      <mat-form-field *ngIf="styles.borderColor !== undefined"
+                      appearance="fill" class="mdInput textsingleline">
+        <mat-label>{{'propertiesPanel.borderColor' | translate }}</mat-label>
+        <input matInput type="text" [value]="styles.borderColor"
+               (input)="unitService.updateSelectedElementsStyleProperty('borderColor', $any($event.target).value)">
+        <button mat-icon-button matSuffix (click)="borderColorInput.click()">
+          <mat-icon>edit</mat-icon>
+        </button>
+      </mat-form-field>
+      <input matInput type="color" hidden #borderColorInput
+             [value]="styles.borderColor"
+             (input)="unitService.updateSelectedElementsStyleProperty('borderColor', $any($event.target).value)">
+
       <mat-form-field *ngIf="styles.borderStyle !== undefined"
                       appearance="fill">
         <mat-label>{{'propertiesPanel.borderStyle' | translate }}</mat-label>
@@ -146,7 +149,6 @@ import { UnitService } from 'editor/src/app/services/unit.service';
           </mat-option>
         </mat-select>
       </mat-form-field>
-
       <mat-form-field *ngIf="styles.borderWidth !== undefined"
                       appearance="fill" class="mdInput textsingleline">
         <mat-label>{{'propertiesPanel.borderWidth' | translate }}</mat-label>
@@ -154,11 +156,11 @@ import { UnitService } from 'editor/src/app/services/unit.service';
                [ngModel]="styles.borderWidth"
                (ngModelChange)="unitService.updateSelectedElementsStyleProperty('borderWidth', $event)">
       </mat-form-field>
-    </div>
+    </fieldset>
   `
 })
 export class ElementStylePropertiesComponent {
-  @Input() styles!: BasicStyles & ExtendedStyles;
+  @Input() styles!: BasicStyles & ExtendedStyles | undefined;
 
   constructor(public unitService: UnitService) { }
 }
diff --git a/projects/editor/src/app/components/unit-view/unit-view.component.ts b/projects/editor/src/app/components/unit-view/unit-view.component.ts
index 64d2869a47ece0ceea8182a50a7f948bf739324a..0a6e36624fe98188234f5ee7b8141bc4b84a4070 100644
--- a/projects/editor/src/app/components/unit-view/unit-view.component.ts
+++ b/projects/editor/src/app/components/unit-view/unit-view.component.ts
@@ -1,12 +1,12 @@
 import { Component, OnDestroy } from '@angular/core';
 import { Subject } from 'rxjs';
 import { takeUntil } from 'rxjs/operators';
-import { UnitService } from '../../services/unit.service';
-import { DialogService } from '../../services/dialog.service';
-import { SelectionService } from '../../services/selection.service';
 import { MessageService } from 'common/services/message.service';
 import { ArrayUtils } from 'common/util/array';
 import { Page } from 'common/models/page';
+import { UnitService } from '../../services/unit.service';
+import { DialogService } from '../../services/dialog.service';
+import { SelectionService } from '../../services/selection.service';
 
 @Component({
   selector: 'aspect-unit-view',
diff --git a/projects/editor/src/app/services/dialog.service.ts b/projects/editor/src/app/services/dialog.service.ts
index 86f6863805a82d8287a9e5e7224da278ae976c6d..65b1f9f37a73164c0cc21c35309cf081234dede3 100644
--- a/projects/editor/src/app/services/dialog.service.ts
+++ b/projects/editor/src/app/services/dialog.service.ts
@@ -1,20 +1,23 @@
 import { Injectable } from '@angular/core';
 import { Observable } from 'rxjs';
 import { MatDialog } from '@angular/material/dialog';
+import {
+  DragNDropValueObject,
+  PlayerProperties,
+  TextImageLabel, Label
+} from 'common/models/elements/element';
+import { ClozeDocument } from 'common/models/elements/compound-elements/cloze/cloze';
+import { LikertRowElement } from 'common/models/elements/compound-elements/likert/likert-row';
+import { Section } from 'common/models/section';
+import { SectionInsertDialogComponent } from 'editor/src/app/components/dialogs/section-insert-dialog.component';
+import { LabelEditDialogComponent } from 'editor/src/app/components/dialogs/label-edit-dialog.component';
 import { ConfirmationDialogComponent } from '../components/dialogs/confirmation-dialog.component';
 import { TextEditDialogComponent } from '../components/dialogs/text-edit-dialog.component';
 import { TextEditMultilineDialogComponent } from '../components/dialogs/text-edit-multiline-dialog.component';
 import { RichTextEditDialogComponent } from '../components/dialogs/rich-text-edit-dialog.component';
 import { PlayerEditDialogComponent } from '../components/dialogs/player-edit-dialog.component';
-import { ColumnHeaderEditDialogComponent } from '../components/dialogs/column-header-edit-dialog.component';
 import { LikertRowEditDialogComponent } from '../components/dialogs/likert-row-edit-dialog.component';
 import { DropListOptionEditDialogComponent } from '../components/dialogs/drop-list-option-edit-dialog.component';
-import { RichTextSimpleEditDialogComponent } from '../components/dialogs/rich-text-simple-edit-dialog.component';
-import { DragNDropValueObject, PlayerProperties, TextImageLabel } from 'common/models/elements/element';
-import { ClozeDocument } from 'common/models/elements/compound-elements/cloze/cloze';
-import { LikertRowElement } from 'common/models/elements/compound-elements/likert/likert-row';
-import { SectionInsertDialogComponent } from 'editor/src/app/components/dialogs/section-insert-dialog.component';
-import { Section } from 'common/models/section';
 
 @Injectable({
   providedIn: 'root'
@@ -22,6 +25,13 @@ import { Section } from 'common/models/section';
 export class DialogService {
   constructor(private dialog: MatDialog) { }
 
+  showLabelEditDialog(label: Label): Observable<Label> {
+    const dialogRef = this.dialog.open(LabelEditDialogComponent, {
+      data: { label }
+    });
+    return dialogRef.afterClosed();
+  }
+
   showConfirmDialog(text: string): Observable<boolean> {
     const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
       data: { text }
@@ -57,17 +67,7 @@ export class DialogService {
         defaultFontSize,
         clozeMode: false
       },
-      autoFocus: false
-    });
-    return dialogRef.afterClosed();
-  }
-
-  showRichTextSimpleEditDialog(text: string, defaultFontSize: number): Observable<string> {
-    const dialogRef = this.dialog.open(RichTextSimpleEditDialogComponent, {
-      data: {
-        content: text,
-        defaultFontSize
-      },
+      height: '600px',
       autoFocus: false
     });
     return dialogRef.afterClosed();
@@ -75,7 +75,12 @@ export class DialogService {
 
   showClozeTextEditDialog(document: ClozeDocument, defaultFontSize: number): Observable<string> {
     const dialogRef = this.dialog.open(RichTextEditDialogComponent, {
-      data: { content: document, defaultFontSize, clozeMode: true },
+      data: {
+        content: document,
+        defaultFontSize,
+        clozeMode: true
+      },
+      height: '700px',
       autoFocus: false
     });
     return dialogRef.afterClosed();
@@ -88,16 +93,9 @@ export class DialogService {
     return dialogRef.afterClosed();
   }
 
-  showLikertColumnEditDialog(column: TextImageLabel, defaultFontSize: number): Observable<TextImageLabel> {
-    const dialogRef = this.dialog.open(ColumnHeaderEditDialogComponent, {
-      data: { column, defaultFontSize }
-    });
-    return dialogRef.afterClosed();
-  }
-
-  showLikertRowEditDialog(row: LikertRowElement, columns: TextImageLabel[]): Observable<LikertRowElement> {
+  showLikertRowEditDialog(row: LikertRowElement, options: TextImageLabel[]): Observable<LikertRowElement> {
     const dialogRef = this.dialog.open(LikertRowEditDialogComponent, {
-      data: { row, columns }
+      data: { row, options }
     });
     return dialogRef.afterClosed();
   }
diff --git a/projects/editor/src/app/services/unit.service.ts b/projects/editor/src/app/services/unit.service.ts
index 0545daf1028fe77324ce126dd52ac6855a03eade..b030dbed91a53b2c8b22a481f146d40626ca5c57 100644
--- a/projects/editor/src/app/services/unit.service.ts
+++ b/projects/editor/src/app/services/unit.service.ts
@@ -4,16 +4,14 @@ import { Subject } from 'rxjs';
 import { TranslateService } from '@ngx-translate/core';
 import { FileService } from 'common/services/file.service';
 import { MessageService } from 'common/services/message.service';
-import { DialogService } from './dialog.service';
-import { VeronaAPIService } from './verona-api.service';
-import { SelectionService } from './selection.service';
 import { ArrayUtils } from 'common/util/array';
 import { SanitizationService } from 'common/services/sanitization.service';
 import { Unit } from 'common/models/unit';
 import {
+  CompoundElement,
   DragNDropValueObject, InputElement,
-  InputElementValue, PlayerElement, PlayerProperties, PositionedUIElement, TextImageLabel,
-  UIElement, UIElementType
+  InputElementValue, TextLabel, PlayerElement, PlayerProperties, PositionedUIElement, TextImageLabel,
+  UIElement, UIElementType, UIElementValue
 } from 'common/models/elements/element';
 import { LikertElement } from 'common/models/elements/compound-elements/likert/likert';
 import { ClozeDocument, ClozeElement } from 'common/models/elements/compound-elements/cloze/cloze';
@@ -24,12 +22,16 @@ import { Page } from 'common/models/page';
 import { Section } from 'common/models/section';
 import { ElementFactory } from 'common/util/element.factory';
 import { IDManager } from 'common/util/id-manager';
+import { DialogService } from './dialog.service';
+import { VeronaAPIService } from './verona-api.service';
+import { SelectionService } from './selection.service';
 
 @Injectable({
   providedIn: 'root'
 })
 export class UnitService {
   unit: Unit;
+  idManager = IDManager.getInstance();
 
   elementPropertyUpdated: Subject<void> = new Subject<void>();
 
@@ -44,13 +46,13 @@ export class UnitService {
   }
 
   loadUnitDefinition(unitDefinition: string): void {
-    IDManager.getInstance().reset();
+    this.idManager.reset();
     const unitDef = JSON.parse(unitDefinition);
     if (SanitizationService.isUnitDefinitionOutdated(unitDef)) {
       this.unit = new Unit(this.sanitizationService.sanitizeUnitDefinition(unitDef));
       this.messageService.showMessage(this.translateService.instant('outdatedUnit'));
     } else {
-      this.unit = new Unit(unitDef, IDManager.getInstance());
+      this.unit = new Unit(unitDef, this.idManager);
     }
   }
 
@@ -139,14 +141,19 @@ export class UnitService {
     this.veronaApiService.sendVoeDefinitionChangedNotification(this.unit);
   }
 
-  private freeUpIds(elements: UIElement[]): void { // TODO free up child and value IDs
+  private freeUpIds(elements: UIElement[]): void {
     elements.forEach(element => {
       if (element.type === 'drop-list') {
         ((element as DropListElement).value as DragNDropValueObject[]).forEach((value: DragNDropValueObject) => {
-          IDManager.getInstance().removeId(value.id);
+          this.idManager.removeId(value.id);
+        });
+      }
+      if (element instanceof CompoundElement) {
+        element.getChildElements().forEach((childElement: UIElement) => {
+          this.idManager.removeId(childElement.id);
         });
       }
-      IDManager.getInstance().removeId(element.id);
+      this.idManager.removeId(element.id);
     });
   }
 
@@ -177,25 +184,13 @@ export class UnitService {
 
     if ('value' in newElement && newElement.value instanceof Object) { // replace value Ids with fresh ones (dropList)
       (newElement.value as DragNDropValueObject[]).forEach((valueObject: { id: string }) => {
-        valueObject.id = IDManager.getInstance().getNewID('value');
+        valueObject.id = this.idManager.getNewID('value');
       });
     }
 
     if ('row' in newElement && newElement.rows instanceof Object) { // replace row Ids with fresh ones (likert)
       (newElement.rows as LikertRowElement[]).forEach((rowObject: { id: string }) => {
-        rowObject.id = IDManager.getInstance().getNewID('likert_row');
-      });
-    }
-
-
-    if (newElement instanceof ClozeElement) {
-      element.getChildElements().forEach((childElement: UIElement) => {
-        childElement.id = IDManager.getInstance().getNewID(childElement.type);
-        if (childElement.type === 'drop-list-simple') { // replace value Ids with fresh ones (dropList)
-          (childElement.value as DragNDropValueObject[]).forEach((valueObject: DragNDropValueObject) => {
-            valueObject.id = IDManager.getInstance().getNewID('value');
-          });
-        }
+        rowObject.id = this.idManager.getNewID('likert_row');
       });
     }
     return newElement;
@@ -216,26 +211,18 @@ export class UnitService {
 
   updateElementsProperty(elements: UIElement[],
                          property: string,
-                         value: InputElementValue | TextImageLabel | TextImageLabel[] | ClozeDocument |
-                         DragNDropValueObject[] | null): void {
+                         value: InputElementValue | LikertRowElement[] |
+                         TextLabel | TextLabel[] | ClozeDocument | null): void {
     console.log('updateElementProperty', elements, property, value);
     elements.forEach(element => {
       if (property === 'id') {
-        if (!IDManager.getInstance().isIdAvailable((value as string))) { // prohibit existing IDs
+        if (!this.idManager.isIdAvailable((value as string))) { // prohibit existing IDs
           this.messageService.showError(this.translateService.instant('idTaken'));
         } else {
-          IDManager.getInstance().removeId(element.id);
-          IDManager.getInstance().addID(value as string);
+          this.idManager.removeId(element.id);
+          this.idManager.addID(value as string);
           element.id = value as string;
         }
-      } else if (element.type === 'likert' && property === 'columns') {
-        (element as LikertElement).rows.forEach(row => {
-          row.columnCount = (element as LikertElement).columns.length;
-        });
-      } else if (element.type === 'likert' && property === 'readOnly') {
-        (element as LikertElement).rows.forEach(row => {
-          row.readOnly = value as boolean;
-        });
       } else {
         element.setProperty(property, value);
       }
@@ -244,11 +231,11 @@ export class UnitService {
     this.veronaApiService.sendVoeDefinitionChangedNotification(this.unit);
   }
 
-  updateSelectedElementsPositionProperty(property: string, value: any): void {
+  updateSelectedElementsPositionProperty(property: string, value: UIElementValue): void {
     this.updateElementsPositionProperty(this.selectionService.getSelectedElements(), property, value);
   }
 
-  updateElementsPositionProperty(elements: UIElement[], property: string, value: any): void {
+  updateElementsPositionProperty(elements: UIElement[], property: string, value: UIElementValue): void {
     elements.forEach(element => {
       element.setPositionProperty(property, value);
     });
@@ -256,7 +243,7 @@ export class UnitService {
     this.veronaApiService.sendVoeDefinitionChangedNotification(this.unit);
   }
 
-  updateSelectedElementsStyleProperty(property: string, value: any): void {
+  updateSelectedElementsStyleProperty(property: string, value: UIElementValue): void {
     const elements = this.selectionService.getSelectedElements();
     elements.forEach(element => {
       element.setStyleProperty(property, value);
@@ -265,7 +252,7 @@ export class UnitService {
     this.veronaApiService.sendVoeDefinitionChangedNotification(this.unit);
   }
 
-  updateElementsPlayerProperty(elements: UIElement[], property: string, value: any): void {
+  updateElementsPlayerProperty(elements: UIElement[], property: string, value: UIElementValue): void {
     elements.forEach(element => {
       element.setPlayerProperty(property, value);
     });
@@ -379,7 +366,9 @@ export class UnitService {
       case 'video':
         this.dialogService.showPlayerEditDialog((element as PlayerElement).player)
           .subscribe((result: PlayerProperties) => {
-            Object.keys(result).forEach(key => this.updateElementsPlayerProperty([element], key, result[key]));
+            Object.keys(result).forEach(
+              key => this.updateElementsPlayerProperty([element], key, result[key] as UIElementValue)
+            );
           });
         break;
       // no default
@@ -387,7 +376,7 @@ export class UnitService {
   }
 
   getNewValueID(): string {
-    return IDManager.getInstance().getNewID('value');
+    return this.idManager.getNewID('value');
   }
 
   /* Used by props panel to show available dropLists to connect */
diff --git a/projects/editor/src/app/services/verona-api.service.ts b/projects/editor/src/app/services/verona-api.service.ts
index 79e97ce8bf9739f768de7d2bb0cf809dca5ed2ba..d35bd174b79745e472eeebb64524210ef8ab2dbc 100644
--- a/projects/editor/src/app/services/verona-api.service.ts
+++ b/projects/editor/src/app/services/verona-api.service.ts
@@ -1,8 +1,8 @@
 import { Injectable } from '@angular/core';
 import { fromEvent, Observable, Subject } from 'rxjs';
-import packageJSON from '../../../../../package.json';
 import { Unit } from 'common/models/unit';
 import { AnswerScheme } from 'common/models/elements/element';
+import packageJSON from '../../../../../package.json';
 
 @Injectable({
   providedIn: 'root'
@@ -12,7 +12,7 @@ export class VeronaAPIService {
   private _voeStartCommand = new Subject<VoeStartCommand>(); // TODO proper interfaces
   private _voeGetDefinitionRequest = new Subject<VoeGetDefinitionRequest>();
 
-  private isStandalone = (): boolean => window === window.parent;
+  private isStandalone = window === window.parent;
 
   constructor() {
     fromEvent(window, 'message')
@@ -37,7 +37,7 @@ export class VeronaAPIService {
 
   private send(message: Record<string, string | AnswerScheme[]>): void {
     // prevent posts in local (dev) mode
-    if (!this.isStandalone()) {
+    if (!this.isStandalone) {
       window.parent.postMessage(message, '*');
     } else {
       // console.log(`player: ${message.type}`);
diff --git a/projects/editor/src/app/text-editor-simple/rich-text-editor-simple.component.css b/projects/editor/src/app/text-editor-simple/rich-text-editor-simple.component.css
index cd115f951937d19dd772736efabbf899ac634a48..4790c9456292741f6bca04defdcf2cc69566a8f1 100644
--- a/projects/editor/src/app/text-editor-simple/rich-text-editor-simple.component.css
+++ b/projects/editor/src/app/text-editor-simple/rich-text-editor-simple.component.css
@@ -1,5 +1,5 @@
 :host ::ng-deep div.ProseMirror {
-  min-height: 100px;
+  min-height: 60px;
   border: 1px solid;
 }
 
@@ -9,7 +9,6 @@
 }
 
 .editor-control-panel {
-  margin-bottom: 20px;
   background: linear-gradient(to top right, #FFF5F8, #FAFAFA);
   font: unset;
   max-width: 1000px;
diff --git a/projects/editor/src/app/text-editor-simple/rich-text-editor-simple.component.html b/projects/editor/src/app/text-editor-simple/rich-text-editor-simple.component.html
index 2f0badcbef9f8a8d5fc34b3e93b3058d883a441b..163e3a2d3604b71f9d784df1ae6f8ce44fc23644 100644
--- a/projects/editor/src/app/text-editor-simple/rich-text-editor-simple.component.html
+++ b/projects/editor/src/app/text-editor-simple/rich-text-editor-simple.component.html
@@ -1,4 +1,4 @@
-<div fxLayout="row" class="editor-control-panel" mat-dialog-title>
+<div fxLayout="row" class="editor-control-panel">
   <div fxLayout="row">
     <fieldset fxLayout="row">
       <legend>Schriftauszeichnung</legend>
@@ -112,7 +112,7 @@
   </fieldset>
 </div>
 
-<tiptap-editor [editor]="editor" [ngModel]="content" mat-dialog-content
+<tiptap-editor [editor]="editor" [ngModel]="content"
                [style.font-size.px]="defaultFontSize"
                (ngModelChange)="contentChange.emit($event)">
 </tiptap-editor>
diff --git a/projects/editor/src/app/text-editor-simple/rich-text-editor-simple.component.ts b/projects/editor/src/app/text-editor-simple/rich-text-editor-simple.component.ts
index 4ceacaf227a6704188247a62455115c75e89ab9d..fafc7488ebf02b572a0c0de4aada30836ca5be1b 100644
--- a/projects/editor/src/app/text-editor-simple/rich-text-editor-simple.component.ts
+++ b/projects/editor/src/app/text-editor-simple/rich-text-editor-simple.component.ts
@@ -2,7 +2,6 @@ import {
   Component, EventEmitter, Input, Output
 } from '@angular/core';
 import { Editor, mergeAttributes } from '@tiptap/core';
-import StarterKit from '@tiptap/starter-kit';
 import { Underline } from '@tiptap/extension-underline';
 import { Superscript } from '@tiptap/extension-superscript';
 import { Subscript } from '@tiptap/extension-subscript';
@@ -10,6 +9,12 @@ import { Paragraph } from '@tiptap/extension-paragraph';
 import { TextStyle } from '@tiptap/extension-text-style';
 import { Color } from '@tiptap/extension-color';
 import { Highlight } from '@tiptap/extension-highlight';
+import { Document } from '@tiptap/extension-document';
+import { Text } from '@tiptap/extension-text';
+import { ListItem } from '@tiptap/extension-list-item';
+import { Strike } from '@tiptap/extension-strike';
+import { Bold } from '@tiptap/extension-bold';
+import { Italic } from '@tiptap/extension-italic';
 
 @Component({
   selector: 'aspect-rich-text-editor-simple',
@@ -25,8 +30,10 @@ export class RichTextEditorSimpleComponent {
   selectedHighlightColor: string = 'lightgrey';
 
   editor = new Editor({
-    extensions: [StarterKit, Underline, Superscript, Subscript,
+    extensions: [Document, Text, ListItem,
+      Underline, Superscript, Subscript,
       TextStyle, Color,
+      Bold, Italic, Strike,
       Highlight.configure({
         multicolor: true
       }),
diff --git a/projects/editor/src/app/text-editor/extensions/hanging-indent.ts b/projects/editor/src/app/text-editor/extensions/hanging-indent.ts
index 7442817b58266280d3a3abfc4150bd69b6f7ca01..581d00878945b5c266e534a5d9521b9212aac5b7 100644
--- a/projects/editor/src/app/text-editor/extensions/hanging-indent.ts
+++ b/projects/editor/src/app/text-editor/extensions/hanging-indent.ts
@@ -57,7 +57,7 @@ export const HangingIndent = Extension.create({
     const updateIndentLevel = (tr: Transaction, hangingIndent: boolean, indentSize: number): Transaction => {
       const { doc, selection } = tr;
 
-      if (doc && selection && (selection instanceof TextSelection || selection instanceof AllSelection)) {
+      if (doc && selection && (selection instanceof TextSelection)) {
         const { from, to } = selection;
         doc.nodesBetween(from, to, (node, pos) => {
           setNodeIndentMarkup(tr, pos, hangingIndent, indentSize);
diff --git a/projects/editor/src/app/text-editor/rich-text-editor.component.css b/projects/editor/src/app/text-editor/rich-text-editor.component.css
index 2add2430f5e55778e6cfc197a2e3aa95fb87bec4..fad268e1740fe23c3db635fde262c9df648c5c3c 100644
--- a/projects/editor/src/app/text-editor/rich-text-editor.component.css
+++ b/projects/editor/src/app/text-editor/rich-text-editor.component.css
@@ -1,5 +1,8 @@
+tiptap-editor {
+  height: 57%;
+}
 :host ::ng-deep div.ProseMirror {
-  min-height: 300px;
+  height: 99%;
   border: 1px solid;
 }
 
diff --git a/projects/editor/src/app/text-editor/rich-text-editor.component.html b/projects/editor/src/app/text-editor/rich-text-editor.component.html
index 4991d39c035fae146d57bc84d5e6e36f35ab6d5a..07efd514eb517757bedf3ed4abbc48b4e4a56aa8 100644
--- a/projects/editor/src/app/text-editor/rich-text-editor.component.html
+++ b/projects/editor/src/app/text-editor/rich-text-editor.component.html
@@ -208,6 +208,8 @@
       <mat-menu #specialCharsMenu="matMenu" yPosition="above">
         <button mat-button (click)="insertSpecialChar('&nbsp;')"
                 [matTooltip]="'Geschütztes Leerzeichen'">&blank;</button>
+        <button mat-button (click)="insertSpecialChar('&#8239;')"
+                [matTooltip]="'Geschütztes Leerzeichen (schmal)'">&blank;<sub>2</sub></button>
         <button mat-button (click)="insertSpecialChar('&ndash;')">&ndash;</button>
         <button mat-button (click)="insertSpecialChar('&female;')">&female;</button>
         <button mat-button (click)="insertSpecialChar('&male;')">&male;</button>
@@ -252,7 +254,7 @@
         <button mat-button (click)="insertSpecialChar('&diams;')">&diams;</button>
       </mat-menu>
       <button mat-icon-button matTooltip="Bild" [matTooltipShowDelay]="300"
-              (click)="addImage()">
+              (click)="insertImage()">
         <mat-icon>image</mat-icon>
       </button>
       <button mat-icon-button matTooltip="Zitat" [matTooltipShowDelay]="300"
diff --git a/projects/editor/src/app/text-editor/rich-text-editor.component.ts b/projects/editor/src/app/text-editor/rich-text-editor.component.ts
index c5f4162f03ca467773a32603a05e8a041c675f55..26eda925dee280bd9efc0b9a07b7f9fabc724142 100644
--- a/projects/editor/src/app/text-editor/rich-text-editor.component.ts
+++ b/projects/editor/src/app/text-editor/rich-text-editor.component.ts
@@ -3,7 +3,6 @@ import {
   AfterViewInit, Injector, OnInit
 } from '@angular/core';
 import { Editor } from '@tiptap/core';
-import StarterKit from '@tiptap/starter-kit';
 import { Underline } from '@tiptap/extension-underline';
 import { Superscript } from '@tiptap/extension-superscript';
 import { Subscript } from '@tiptap/extension-subscript';
@@ -14,13 +13,19 @@ import { TextAlign } from '@tiptap/extension-text-align';
 import { Heading } from '@tiptap/extension-heading';
 import { Image } from '@tiptap/extension-image';
 import { Blockquote } from '@tiptap/extension-blockquote';
+import { Document } from '@tiptap/extension-document';
+import { Text } from '@tiptap/extension-text';
+import { ListItem } from '@tiptap/extension-list-item';
+import { Bold } from '@tiptap/extension-bold';
+import { Italic } from '@tiptap/extension-italic';
+import { Strike } from '@tiptap/extension-strike';
+import { FileService } from 'common/services/file.service';
 import { Indent } from './extensions/indent';
 import { HangingIndent } from './extensions/hanging-indent';
 import { ParagraphExtension } from './extensions/paragraph-extension';
 import { FontSize } from './extensions/font-size';
 import { BulletListExtension } from './extensions/bullet-list';
 import { OrderedListExtension } from './extensions/ordered-list';
-import { FileService } from 'common/services/file.service';
 import ToggleButtonComponentExtension from './angular-node-views/toggle-button-component-extension';
 import DropListComponentExtension from './angular-node-views/drop-list-component-extension';
 import TextFieldComponentExtension from './angular-node-views/text-field-component-extension';
@@ -43,8 +48,11 @@ export class RichTextEditorComponent implements OnInit, AfterViewInit {
   bulletListStyle: string = 'disc';
   orderedListStyle: string = 'decimal';
 
-  defaultExtensions = [StarterKit, Underline, Superscript, Subscript,
+  defaultExtensions = [
+    Document, Text, ListItem,
+    Underline, Superscript, Subscript,
     TextStyle, Color,
+    Bold, Italic, Strike,
     Highlight.configure({
       multicolor: true
     }),
@@ -66,6 +74,7 @@ export class RichTextEditorComponent implements OnInit, AfterViewInit {
     HangingIndent,
     Image.configure({
       inline: true,
+      allowBase64: true,
       HTMLAttributes: {
         style: 'display: inline-block; height: 1em; vertical-align: middle'
       }
@@ -202,7 +211,7 @@ export class RichTextEditorComponent implements OnInit, AfterViewInit {
     this.editor.commands.unhangIndent(this.selectedIndentSize);
   }
 
-  async addImage(): Promise<void> {
+  async insertImage(): Promise<void> {
     const mediaSrc = await FileService.loadImage();
     this.editor.commands.setImage({ src: mediaSrc });
   }
diff --git a/projects/editor/src/assets/i18n/de.json b/projects/editor/src/assets/i18n/de.json
index a11c716c717a6be55ba8acdd171a28708db712e8..3a06ca2f90bbc34d9bd6897f606df41162f3c551 100644
--- a/projects/editor/src/assets/i18n/de.json
+++ b/projects/editor/src/assets/i18n/de.json
@@ -4,6 +4,8 @@
   "page": "Seite",
   "rows": "Zeilen",
   "columns": "Spalten",
+  "column": "Spalte",
+  "row": "Zeile",
   "forward": "nach vorn",
   "backward": "nach hinten",
   "delete": "Löschen",
@@ -60,8 +62,8 @@
     "useMinHeight": "Mindesthöhe setzen",
     "minHeight": "Mindesthöhe",
     "grid": "Raster",
-    "column": "Spalte",
-    "row": "Zeile",
+    "column": "vertikal",
+    "row": "horizontal",
     "columnRange": "Spaltenspanne",
     "rowRange": "Zeilenspanne",
     "margin": "Abstand",
@@ -74,7 +76,7 @@
     "id": "ID",
     "label": "Beschriftung",
     "text": "Text",
-    "borderRadius": "Kantenradius",
+    "borderRadius": "Radius",
     "highlightable": "Markieren erlauben",
     "highlightableYellow": "Gelb",
     "highlightableTurquoise": "Türkis",
@@ -100,11 +102,12 @@
     "true": "wahr",
     "false": "falsch",
     "appearance": "Aussehen",
-    "strikeOtherOptions": "Andere Optionen durchstreichen",
+    "strikeOtherOptions": "Nicht gewählte Optionen durchstreichen",
+    "strikeSelectedOption": "Gewählte Option durchstreichen",
     "minLength": "Minimallänge",
     "minValue": "Minimalwert",
     "minLengthWarnMessage": "Minimalwert Warnmeldung",
-    "maxLength": "Maximalwert",
+    "maxLength": "Maximallänge",
     "maxValue": "Maximalwert",
     "showValues": "Zeige Start- und Endwert",
     "barStyle": "Zahlenstrahl-Modus",
@@ -126,7 +129,7 @@
     "inputAssistancePosition": "Eingabehilfeposition",
     "floating": "schwebend",
     "showSoftwareKeyboard": "Tastatur einblenden",
-    "softwareKeyboardShowFrench": "Französische Sonderzeichen",
+    "softwareKeyboardShowFrench": "Tastatur: Französische Sonderzeichen",
     "lineColoring": "Zeilenfärbung",
     "lineColoringColor": "Zeilenfarbe",
     "scale": "Skalieren",
@@ -144,9 +147,9 @@
     "deleteElement": "Element löschen",
     "noElementSelected": "Kein Element ausgewählt",
     "spellCorrectButtonLabel": "Wort zum Korrigieren",
-    "borderColor": "Randfarbe",
-    "borderWidth": "Randstärke",
-    "borderStyle": "Linienstil",
+    "borderColor": "Farbe",
+    "borderWidth": "Stärke",
+    "borderStyle": "Stil",
     "selectionColor": "Auswahlfarbe",
     "flex": "Dynamisch zentriert",
     "fixedSize": "Feste Abmessungen",
@@ -157,7 +160,11 @@
     "outline": "Umrandet",
     "dynamicWidth": "Dynamische Breite",
     "verticalOrientation": "vertikale Ausrichtung",
-    "copyOnDrop": "Elemente kopieren"
+    "copyOnDrop": "Elemente kopieren",
+    "hasBorderBottom": "Kante oben",
+    "hasBorderTop": "Kante unten",
+    "hasBorderLeft": "Kante links",
+    "hasBorderRight": "Kante rechts"
   },
   "player": {
     "autoStart": "Autostart (nicht für Tablets)",
@@ -187,20 +194,24 @@
     "button": "Navigationsknopf",
     "frame": "Rahmen",
     "text-field": "Eingabefeld",
+    "text-field-simple": "Eingabefeld",
     "text-area": "Eingabebereich",
     "checkbox": "Kontrollkästchen",
     "dropdown": "Klappliste",
     "radio": "Optionsfelder",
+    "radio-group-images": "Optionsfelder mit Bild",
     "simple": "mit Text",
     "complex": "mit Bild",
     "drop-list": "Ablegeliste",
+    "drop-list-simple": "Ablegeliste",
     "image": "Bild",
     "audio": "Audio",
     "video": "Video",
     "likert": "Optionentabelle",
     "cloze": "Lückentext",
     "slider": "Schieberegler",
-    "spell-correct": "Wort korrigieren"
+    "spell-correct": "Wort korrigieren",
+    "toggle-button": "Optionsfeld"
   },
   "section-menu": {
     "height": "Höhe",
@@ -219,5 +230,8 @@
   "Bitte kopierten Abschnitt einfügen": "Bitte kopierten Abschnitt einfügen",
   "Doppelte IDs festgestellt. Weiter mit neu generierten IDs?": "Doppelte IDs festgestellt. Weiter mit neu generierten IDs?",
   "Abschnitt wurde erfolgreich gelesen.": "Abschnitt wurde erfolgreich gelesen.",
-  "Fehler beim Lesen des Abschnitts!": "Fehler beim Lesen des Abschnitts!"
+  "Fehler beim Lesen des Abschnitts!": "Fehler beim Lesen des Abschnitts!",
+  "limitItemPerRow": "Elemente je Zeile begrenzen",
+  "numberGreater0": "Zahlenwert größer 0",
+  "itemsPerRow": "Anzahl der Elemente"
 }
diff --git a/projects/editor/src/styles.css b/projects/editor/src/styles.css
index a6e109e2280b070a58c412ab458211ee452bf4ab..096a900cbfd93d3ef6f5039ccad6e69f54bc1e9a 100644
--- a/projects/editor/src/styles.css
+++ b/projects/editor/src/styles.css
@@ -2,17 +2,7 @@ html, body { height: 100%; }
 
 .mat-expansion-panel-content {font: unset !important;}
 
-.snackbar-warning {border: 3px double #ff4d4d}
-.snackbar-error {background-color: #ff4d4d}
-.snackbar-success {background-color: green}
-
-.cdk-drag {
-  cursor: grab;
-}
-.cdk-drag-dragging {
-  cursor: grabbing;
-}
-
+/* TODO needed? */
 .mat-dialog-content {
   border: 1px solid lightgray;
   margin: -13px !important;
diff --git a/projects/player/modules/logging/services/log.service.ts b/projects/player/modules/logging/services/log.service.ts
index 5083b13705036a12703bcde1cca9979c6e260324..22aefe204cd96fd62139b629677f2a3c3460fb3d 100644
--- a/projects/player/modules/logging/services/log.service.ts
+++ b/projects/player/modules/logging/services/log.service.ts
@@ -11,28 +11,28 @@ export class LogService {
   // eslint-disable-next-line  @typescript-eslint/no-explicit-any
   static error(...args: any[]): void {
     if (LogService.level <= LogLevel.ERROR) {
-      window.console.error.apply( console, args );
+      window.console.error.apply(console, args);
     }
   }
 
   // eslint-disable-next-line  @typescript-eslint/no-explicit-any
   static warn(...args: any[]): void {
     if (LogService.level <= LogLevel.WARN) {
-      window.console.warn.apply( console, args );
+      window.console.warn.apply(console, args);
     }
   }
 
   // eslint-disable-next-line  @typescript-eslint/no-explicit-any
   static info(...args: any[]): void {
     if (LogService.level <= LogLevel.INFO) {
-      window.console.info.apply( console, args );
+      window.console.info.apply(console, args);
     }
   }
 
   // eslint-disable-next-line  @typescript-eslint/no-explicit-any
   static log(...args: any[]): void {
     if (LogService.level <= LogLevel.LOG) {
-      window.console.log.apply( console, args );
+      window.console.log.apply(console, args);
     }
   }
 }
diff --git a/projects/player/src/app/app.module.ts b/projects/player/src/app/app.module.ts
index ddc8d997896048ce69a5d70b94e27ac03ca7c8b9..2a97aad7adc05cdb4173d258e422f615dd903101 100644
--- a/projects/player/src/app/app.module.ts
+++ b/projects/player/src/app/app.module.ts
@@ -5,10 +5,12 @@ import { CommonModule } from '@angular/common';
 import { createCustomElement } from '@angular/elements';
 import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
 import { OverlayModule } from '@angular/cdk/overlay';
+import { SharedModule } from 'common/shared.module';
+import { KeyInputModule } from 'player/modules/key-input/key-input.module';
+import { UnitMenuModule } from 'player/modules/unit-menu/unit-menu.module';
 import { AppComponent } from './app.component';
 import { PageComponent } from './components/page/page.component';
 import { SectionComponent } from './components/section/section.component';
-import { SharedModule } from 'common/shared.module';
 import { PlayerTranslateLoader } from './classes/player-translate-loader';
 import { PagesLayoutComponent } from './components/layouts/pages-layout/pages-layout.component';
 import { PageLabelDirective } from './directives/page-label.directive';
@@ -36,9 +38,7 @@ import {
   InteractiveGroupElementComponent
 } from './components/elements/interactive-group-element/interactive-group-element.component';
 import { PlayerLayoutComponent } from './components/layouts/player-layout/player-layout.component';
-import { KeyInputModule } from 'player/modules/key-input/key-input.module';
 import { UnitStateDirective } from './directives/unit-state.directive';
-import { UnitMenuModule } from 'player/modules/unit-menu/unit-menu.module';
 import { ValidPagesPipe } from './pipes/valid-pages.pipe';
 import { ScrollPagesPipe } from './pipes/scroll-pages.pipe';
 import { AlwaysVisiblePagePipe } from './pipes/always-visible-page.pipe';
@@ -46,6 +46,7 @@ import { PageIndexPipe } from './pipes/page-index.pipe';
 import { PlayerStateDirective } from './directives/player-state.directive';
 import { SectionVisibilityHandlingDirective } from './directives/section-visibility-handling.directive';
 import { UnitComponent } from './components/unit/unit.component';
+import { PageScrollButtonComponent } from './components/page-scroll-button/page-scroll-button.component';
 
 @NgModule({
   declarations: [
@@ -75,7 +76,8 @@ import { UnitComponent } from './components/unit/unit.component';
     PageIndexPipe,
     PlayerStateDirective,
     SectionVisibilityHandlingDirective,
-    UnitComponent
+    UnitComponent,
+    PageScrollButtonComponent
   ],
   imports: [
     BrowserModule,
diff --git a/projects/player/src/app/components/elements/base-group-element/base-group-element.component.ts b/projects/player/src/app/components/elements/base-group-element/base-group-element.component.ts
index 81fccb9f14aaaefa96315c390d4516d85040675e..80df78cd5ccf5d42be19286b364e1bf075313150 100644
--- a/projects/player/src/app/components/elements/base-group-element/base-group-element.component.ts
+++ b/projects/player/src/app/components/elements/base-group-element/base-group-element.component.ts
@@ -22,7 +22,7 @@ export class BaseGroupElementComponent extends ElementGroupDirective implements
 
   ngOnInit(): void {
     this.baseElementComponent =
-      this.elementComponentContainer.createComponent(this.elementModel.getComponentFactory()).instance;
+      this.elementComponentContainer.createComponent(this.elementModel.getElementComponent()).instance;
     this.baseElementComponent.elementModel = this.elementModel;
   }
 
diff --git a/projects/player/src/app/components/layouts/pages-layout/pages-layout.component.css b/projects/player/src/app/components/layouts/pages-layout/pages-layout.component.css
index 24c90f70688c6a3ebca611da04ac4a1ac8c7ea8c..f711044e92da311fed65016c8edc0583c449d118 100644
--- a/projects/player/src/app/components/layouts/pages-layout/pages-layout.component.css
+++ b/projects/player/src/app/components/layouts/pages-layout/pages-layout.component.css
@@ -3,8 +3,8 @@
 }
 
 .concat-scroll-snap {
-  scroll-snap-type: both mandatory;
-  scroll-padding: 10px;
+  scroll-snap-type: y mandatory;
+  scroll-padding: 0;
 }
 
 .page-container{
diff --git a/projects/player/src/app/components/layouts/pages-layout/pages-layout.component.html b/projects/player/src/app/components/layouts/pages-layout/pages-layout.component.html
index b306807775f34cc3ad3ad9ca5a49dde9ac8014ef..626bd0d543ff6a7ffb376419b4923ec9abeafc69 100644
--- a/projects/player/src/app/components/layouts/pages-layout/pages-layout.component.html
+++ b/projects/player/src/app/components/layouts/pages-layout/pages-layout.component.html
@@ -9,8 +9,10 @@
 </div>
 
 <ng-template #alwaysVisiblePageView>
-  <div *ngIf="alwaysVisiblePage"
+  <aspect-page-scroll-button
+      *ngIf="alwaysVisiblePage"
       class="page-container"
+      [isSnapMode]="false"
       [style.max-height.%]="aspectRatioColumn.alwaysVisiblePage"
       [style.max-width.%]="aspectRatioRow.alwaysVisiblePage">
     <div #alwaysVisiblePageContainer
@@ -33,15 +35,18 @@
         </aspect-page>
       </div>
     </div>
-  </div>
+  </aspect-page-scroll-button>
 </ng-template>
 
 <ng-template #scrollPagesView>
   <ng-container *ngIf="hasScrollPages">
-    <div class="page-container"
+    <aspect-page-scroll-button
+        class="page-container"
+        [isSnapMode]="scrollPageMode === 'concat-scroll-snap'"
         [class.concat-scroll-snap]="scrollPageMode === 'concat-scroll-snap'"
         [style.max-height.%]="aspectRatioColumn.scrollPages"
-        [style.max-width.%]="aspectRatioRow.scrollPages">
+        [style.max-width.%]="aspectRatioRow.scrollPages"
+        (scrollToNextPage)="scrollToNextPage()">
       <div #pagesScrolledContainer
           [class.center-pages]="layoutAlignment === 'column' || !alwaysVisiblePage"
           [class.left-container]="alwaysVisiblePage && alwaysVisiblePagePosition === 'right'"
@@ -51,7 +56,7 @@
             [ngTemplateOutletContext]="{pagesContainer: pagesScrolledContainer}">
         </ng-container>
       </div>
-    </div>
+    </aspect-page-scroll-button>
   </ng-container>
 </ng-template>
 
@@ -83,7 +88,9 @@
 
 <ng-template #scrollPagesScrolledView let-pagesContainer>
   <ng-container *ngFor="let page of scrollPages; let i = index; let last = last">
-    <div [style.min-height]="'calc(100vh - ' + (page.margin * 2) + 'px)'"
+    <div [style.min-height]="scrollPageMode === 'concat-scroll-snap' ?
+                             'calc(100vh - ' + (page.margin * 2) + 'px)' :
+                             'unset'"
         [style.background-color]="page.backgroundColor"
         [class.concat-scroll-snap-align]="scrollPageMode === 'concat-scroll-snap'"
         [style.max-width]="page.hasMaxWidth ? page.maxWidth + 'px' : '100%'"
@@ -97,6 +104,7 @@
       </div>
       <aspect-page
           [pageIndex]="pages | pageIndex: page"
+          [scrollPageIndex]="i"
           [pagesContainer]="pagesContainer"
           [page]="page"
           [isLastPage]="last"
diff --git a/projects/player/src/app/components/layouts/pages-layout/pages-layout.component.ts b/projects/player/src/app/components/layouts/pages-layout/pages-layout.component.ts
index bd413325b70689ca9cc37561d5a18534d517de7d..cf2ae2f82cf88f34c1a44e3a2126cb69af13d89c 100644
--- a/projects/player/src/app/components/layouts/pages-layout/pages-layout.component.ts
+++ b/projects/player/src/app/components/layouts/pages-layout/pages-layout.component.ts
@@ -3,12 +3,12 @@ import {
 } from '@angular/core';
 import { Subject } from 'rxjs';
 import { takeUntil } from 'rxjs/operators';
-import { NativeEventService } from '../../../services/native-event.service';
 import { Page } from 'common/models/page';
 import { VeronaPostService } from 'player/modules/verona/services/verona-post.service';
 import { NavigationService } from 'player/src/app/services/navigation.service';
 import { VopPageNavigationCommand } from 'player/modules/verona/models/verona';
 import { VeronaSubscriptionService } from 'player/modules/verona/services/verona-subscription.service';
+import { NativeEventService } from '../../../services/native-event.service';
 
 @Component({
   selector: 'aspect-pages-layout',
@@ -134,7 +134,7 @@ export class PagesLayoutComponent implements OnInit, AfterViewInit, OnDestroy {
   }
 
   private calculatePagesMaxWidth(): void {
-    this.maxWidth.alwaysVisiblePage = this.getAbsolutePageWidth(this.alwaysVisiblePage);
+    this.maxWidth.alwaysVisiblePage = PagesLayoutComponent.getAbsolutePageWidth(this.alwaysVisiblePage);
     this.maxWidth.scrollPages = this.getScrollPagesWidth();
     this.maxWidth.allPages = Math.max(this.maxWidth.alwaysVisiblePage, this.maxWidth.scrollPages);
   }
@@ -153,13 +153,19 @@ export class PagesLayoutComponent implements OnInit, AfterViewInit, OnDestroy {
 
   private getScrollPagesWidth(): number {
     return this.hasScrollPages ?
-      Math.max(...this.scrollPages.map((page: Page): number => this.getAbsolutePageWidth(page))) : 0;
+      Math.max(...this.scrollPages.map((page: Page): number => PagesLayoutComponent.getAbsolutePageWidth(page))) : 0;
   }
 
-  private getAbsolutePageWidth = (page: Page | null): number => ((page) ? 2 * page.margin + page.maxWidth : 0);
+  private static getAbsolutePageWidth = (page: Page | null): number => ((page) ? 2 * page.margin + page.maxWidth : 0);
 
   ngOnDestroy(): void {
     this.ngUnsubscribe.next();
     this.ngUnsubscribe.complete();
   }
+
+  scrollToNextPage() {
+    if (this.selectedIndex < this.scrollPages.length - 1) {
+      this.selectIndex.next(this.selectedIndex + 1);
+    }
+  }
 }
diff --git a/projects/player/src/app/components/page-scroll-button/page-scroll-button.component.html b/projects/player/src/app/components/page-scroll-button/page-scroll-button.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..ba9a935a287c536326fdb06da560d4f08b23210b
--- /dev/null
+++ b/projects/player/src/app/components/page-scroll-button/page-scroll-button.component.html
@@ -0,0 +1,17 @@
+<ng-content></ng-content>
+<div fxLayout="column" fxLayoutAlign="center end"
+     class="scroll-button-container">
+  <button *ngIf="isVisible.value"
+          mat-fab
+          class="scroll-button"
+          (contextmenu)="$event.preventDefault()"
+          (pointercancel)="toggleScrolling(false)"
+          (pointerout)="toggleScrolling(false)"
+          (pointerdown)="toggleScrolling(true)"
+          (pointerup)="toggleScrolling(false)"
+          (pointerleave)="toggleScrolling(false)">
+    <mat-icon>arrow_downward</mat-icon>
+  </button>
+</div>
+
+
diff --git a/projects/player/src/app/components/page-scroll-button/page-scroll-button.component.scss b/projects/player/src/app/components/page-scroll-button/page-scroll-button.component.scss
new file mode 100644
index 0000000000000000000000000000000000000000..616da2a411d0f764e084b13b46bfe26a6cb68e56
--- /dev/null
+++ b/projects/player/src/app/components/page-scroll-button/page-scroll-button.component.scss
@@ -0,0 +1,16 @@
+.scroll-button {
+  background-color: #cccccc;
+  opacity: 0.6;
+  pointer-events: all;
+  &:hover {
+    opacity: 0.8;
+  }
+}
+
+.scroll-button-container {
+  height: 0;
+  padding-right: 15px;
+  position: sticky;
+  bottom: 40px;
+  pointer-events: none;
+}
diff --git a/projects/player/src/app/components/page-scroll-button/page-scroll-button.component.spec.ts b/projects/player/src/app/components/page-scroll-button/page-scroll-button.component.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0c79ac29126e149256e13a8e60ef11bb97ae9e64
--- /dev/null
+++ b/projects/player/src/app/components/page-scroll-button/page-scroll-button.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { PageScrollButtonComponent } from './page-scroll-button.component';
+
+describe('PageScrollButtonComponent', () => {
+  let component: PageScrollButtonComponent;
+  let fixture: ComponentFixture<PageScrollButtonComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      declarations: [PageScrollButtonComponent]
+    })
+      .compileComponents();
+  });
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(PageScrollButtonComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/projects/player/src/app/components/page-scroll-button/page-scroll-button.component.ts b/projects/player/src/app/components/page-scroll-button/page-scroll-button.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..97c65dba4d0739de83a17b159d46d95ce6bf09e4
--- /dev/null
+++ b/projects/player/src/app/components/page-scroll-button/page-scroll-button.component.ts
@@ -0,0 +1,77 @@
+import {
+  AfterViewInit, ChangeDetectorRef, Component, ElementRef, EventEmitter, HostListener, Input, OnDestroy, Output
+} from '@angular/core';
+import { BehaviorSubject, Subject } from 'rxjs';
+import { takeUntil } from 'rxjs/operators';
+
+@Component({
+  selector: 'aspect-page-scroll-button',
+  templateUrl: './page-scroll-button.component.html',
+  styleUrls: ['./page-scroll-button.component.scss']
+})
+export class PageScrollButtonComponent implements AfterViewInit, OnDestroy {
+  @HostListener('scroll', ['$event.target'])
+  onScroll(element: HTMLElement) {
+    this.checkScrollPosition(element);
+  }
+
+  @Input() isSnapMode!: boolean;
+
+  @Output() scrollToNextPage: EventEmitter<void> = new EventEmitter<void>();
+
+  isVisible: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
+  scrollIntervalId!: number;
+
+  private ngUnsubscribe = new Subject<void>();
+
+  constructor(private elementRef: ElementRef,
+              private changeDetectorRef: ChangeDetectorRef) {
+    this.isVisible
+      .pipe(takeUntil(this.ngUnsubscribe))
+      .subscribe(value => {
+        if (!value) {
+          this.clearScrollIng();
+        }
+      });
+  }
+
+  ngAfterViewInit(): void {
+    this.checkScrollPosition(this.elementRef.nativeElement);
+    this.changeDetectorRef.detectChanges();
+  }
+
+  private checkScrollPosition(element: HTMLElement): void {
+    this.isVisible.next(element.scrollHeight - element.offsetHeight > element.scrollTop);
+  }
+
+  toggleScrolling(scrolling: boolean) {
+    if (scrolling) {
+      this.scrollIntervalId = setInterval(() => {
+        this.scrollDown();
+      });
+    } else {
+      setTimeout(() => this.clearScrollIng(), 0);
+    }
+  }
+
+  scrollDown(): void {
+    const lastScrollTop = this.elementRef.nativeElement.scrollTop;
+    this.elementRef.nativeElement.scrollTop = lastScrollTop + 2;
+    if (this.isSnapMode && (this.elementRef.nativeElement.scrollTop !== lastScrollTop + 2)) {
+      this.clearScrollIng();
+      // FF needs time to finish concat scroll anmations before setting a new page index
+      setTimeout(() => this.scrollToNextPage.emit(), 100);
+    }
+  }
+
+  private clearScrollIng(): void {
+    if (this.scrollIntervalId) {
+      clearInterval(this.scrollIntervalId);
+    }
+  }
+
+  ngOnDestroy(): void {
+    this.ngUnsubscribe.next();
+    this.ngUnsubscribe.complete();
+  }
+}
diff --git a/projects/player/src/app/components/page/page.component.html b/projects/player/src/app/components/page/page.component.html
index 2a646e071d4f7adaf2ea39d69b1f537726d8e27b..961be3cc6e22d70d1798fdcef9142a5343a12fdb 100644
--- a/projects/player/src/app/components/page/page.component.html
+++ b/projects/player/src/app/components/page/page.component.html
@@ -1,7 +1,7 @@
 <div aspectInViewDetection
      detectionType="top"
      [intersectionContainer]="pagesContainer"
-     (intersecting)="selectedIndexChange.emit(pageIndex)">
+     (intersecting)="selectedIndexChange.emit(scrollPageIndex)">
   <aspect-section
     *ngFor="let section of page.sections"
     class="section"
@@ -18,5 +18,5 @@
 <div aspectInViewDetection
      detectionType="bottom"
      [intersectionContainer]="pagesContainer"
-     (intersecting)="selectedIndexChange.emit(pageIndex)">
+     (intersecting)="selectedIndexChange.emit(scrollPageIndex)">
 </div>
diff --git a/projects/player/src/app/components/page/page.component.ts b/projects/player/src/app/components/page/page.component.ts
index 566cf711e58f64966c76741d64049c733ed8990b..eb08b27574d33d06466e6d0c2e31d447ce83e2fd 100644
--- a/projects/player/src/app/components/page/page.component.ts
+++ b/projects/player/src/app/components/page/page.component.ts
@@ -1,8 +1,8 @@
 import {
   Component, Input, Output, EventEmitter
 } from '@angular/core';
-import { MediaPlayerService } from '../../services/media-player.service';
 import { Page } from 'common/models/page';
+import { MediaPlayerService } from '../../services/media-player.service';
 
 @Component({
   selector: 'aspect-page',
@@ -14,6 +14,7 @@ export class PageComponent {
   @Input() page!: Page;
   @Input() isLastPage!: boolean;
   @Input() pageIndex!: number;
+  @Input() scrollPageIndex!: number;
   @Input() pagesContainer!: HTMLElement;
   @Output() selectedIndexChange = new EventEmitter<number>();
 
diff --git a/projects/player/src/app/directives/in-view-detection.directive.ts b/projects/player/src/app/directives/in-view-detection.directive.ts
index 79a2cdbefaff3e5465f2af1ab0856bb1222e2eca..476e784669c6d86eeb3daddb9c44c5edcf7db3e2 100644
--- a/projects/player/src/app/directives/in-view-detection.directive.ts
+++ b/projects/player/src/app/directives/in-view-detection.directive.ts
@@ -1,6 +1,8 @@
 import {
   Directive, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Output
 } from '@angular/core';
+import { takeUntil } from 'rxjs/operators';
+import { Subject } from 'rxjs';
 import { IntersectionDetector } from '../classes/intersection-detector';
 
 @Directive({
@@ -13,18 +15,22 @@ export class InViewDetectionDirective implements OnInit, OnDestroy {
 
   intersectionDetector!: IntersectionDetector;
 
+  private ngUnsubscribe = new Subject<void>();
+
   constructor(private elementRef: ElementRef) {}
 
   ngOnInit(): void {
-    const constraint = this.detectionType === 'top' ? '0px 0px 0px 0px' : '-95% 0px 0px 0px';
+    const constraint = this.detectionType === 'top' ? '0px 0px -99% 0px' : '99% 0px 0px 0px';
     this.intersectionDetector = new IntersectionDetector(this.intersectionContainer, constraint);
     this.intersectionDetector.observe(this.elementRef.nativeElement);
-    this.intersectionDetector.intersecting.subscribe(() => {
-      this.intersecting.emit();
-    });
+    this.intersectionDetector.intersecting
+      .pipe(takeUntil(this.ngUnsubscribe))
+      .subscribe(() => this.intersecting.emit());
   }
 
   ngOnDestroy(): void {
+    this.ngUnsubscribe.next();
+    this.ngUnsubscribe.complete();
     this.intersectionDetector.disconnect(this.elementRef.nativeElement);
   }
 }
diff --git a/projects/player/src/app/directives/player-state.directive.ts b/projects/player/src/app/directives/player-state.directive.ts
index 366af704508a2fb5235da64ad36c91f3e8ec11e1..68d71f7510a60a4ae6b374c97049cf8bad0fce19 100644
--- a/projects/player/src/app/directives/player-state.directive.ts
+++ b/projects/player/src/app/directives/player-state.directive.ts
@@ -1,8 +1,12 @@
-import { Directive, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';
+import {
+  Directive, Input, OnChanges, OnInit, SimpleChanges
+} from '@angular/core';
 import {
   PlayerState, RunningState
 } from 'player/modules/verona/models/verona';
-import { BehaviorSubject, Subject } from 'rxjs';
+import {
+  BehaviorSubject, map, merge, Subject
+} from 'rxjs';
 import { VeronaSubscriptionService } from 'player/modules/verona/services/verona-subscription.service';
 import { VeronaPostService } from 'player/modules/verona/services/verona-post.service';
 import { takeUntil } from 'rxjs/operators';
@@ -25,7 +29,6 @@ export class PlayerStateDirective implements OnInit, OnChanges {
 
   ngOnInit(): void {
     this.initSubscriptions();
-    this.sendVopStateChangedNotification();
   }
 
   ngOnChanges(changes: SimpleChanges): void {
@@ -35,15 +38,15 @@ export class PlayerStateDirective implements OnInit, OnChanges {
   }
 
   private initSubscriptions(): void {
-    this.veronaSubscriptionService.vopContinueCommand
-      .pipe(takeUntil(this.ngUnsubscribe))
-      .subscribe(() => this.setAndSendRunningState(true));
-    this.veronaSubscriptionService.vopStopCommand
-      .pipe(takeUntil(this.ngUnsubscribe))
-      .subscribe(()  => this.setAndSendRunningState(false));
-    this.veronaSubscriptionService.vopGetStateRequest
-      .pipe(takeUntil(this.ngUnsubscribe))
-      .subscribe(message => this.setAndSendRunningState((!message.stop && this.state === 'running')));
+    merge(
+      this.veronaSubscriptionService.vopContinueCommand
+        .pipe(map(() => true)),
+      this.veronaSubscriptionService.vopStopCommand
+        .pipe(map(() => false)),
+      this.veronaSubscriptionService.vopGetStateRequest
+        .pipe(map(message => (!message.stop && this.state === 'running')))
+    ).pipe(takeUntil(this.ngUnsubscribe))
+      .subscribe(isRunning => this.setAndSendRunningState(isRunning));
   }
 
   private get state(): RunningState {
diff --git a/projects/player/src/app/directives/scroll-to-index.directive.ts b/projects/player/src/app/directives/scroll-to-index.directive.ts
index 9cc0c54148799a0e89b01445af5658268b3c6250..02c42aec571c7e301eda3fc06251c0db92287e97 100644
--- a/projects/player/src/app/directives/scroll-to-index.directive.ts
+++ b/projects/player/src/app/directives/scroll-to-index.directive.ts
@@ -1,22 +1,33 @@
 import {
-  Directive, ElementRef, Input, OnInit
+  Directive, ElementRef, Input, OnDestroy, OnInit
 } from '@angular/core';
 import { Subject } from 'rxjs';
+import { takeUntil } from 'rxjs/operators';
 
 @Directive({
   selector: '[aspectScrollToIndex]'
 })
-export class ScrollToIndexDirective implements OnInit {
+export class ScrollToIndexDirective implements OnInit, OnDestroy {
   @Input() selectIndex!: Subject<number>;
   @Input() index!: number;
 
+  private ngUnsubscribe = new Subject<void>();
+
   constructor(private elementRef: ElementRef) {}
 
   ngOnInit(): void {
-    this.selectIndex.subscribe((selectedIndex: number): void => {
-      if (selectedIndex === this.index) {
-        this.elementRef.nativeElement.scrollIntoView({ behavior: 'smooth' });
-      }
-    });
+    this.selectIndex
+      .pipe(takeUntil(this.ngUnsubscribe))
+      .subscribe((selectedIndex: number): void => {
+        if (selectedIndex === this.index) {
+          // timeout is required because of side effects of concat scroll
+          setTimeout(() => this.elementRef.nativeElement.scrollIntoView({ behavior: 'smooth', block: 'start' }));
+        }
+      });
+  }
+
+  ngOnDestroy(): void {
+    this.ngUnsubscribe.next();
+    this.ngUnsubscribe.complete();
   }
 }
diff --git a/projects/player/src/app/directives/unit-state.directive.ts b/projects/player/src/app/directives/unit-state.directive.ts
index ad4eb142fcc4cde3b2bd92da502290782e22452f..666802c931152a484887d45aa11c6d509b805f57 100644
--- a/projects/player/src/app/directives/unit-state.directive.ts
+++ b/projects/player/src/app/directives/unit-state.directive.ts
@@ -1,13 +1,13 @@
 import { Directive, OnDestroy, OnInit } from '@angular/core';
-import { Subject } from 'rxjs';
+import { debounceTime, merge, Subject } from 'rxjs';
 import { takeUntil } from 'rxjs/operators';
 import { Progress, UnitState } from 'player/modules/verona/models/verona';
-import { UnitStateService } from '../services/unit-state.service';
-import { MediaPlayerService } from '../services/media-player.service';
 import { VeronaSubscriptionService } from 'player/modules/verona/services/verona-subscription.service';
 import { VeronaPostService } from 'player/modules/verona/services/verona-post.service';
-import { ValidationService } from '../services/validation.service';
 import { LogService } from 'player/modules/logging/services/log.service';
+import { UnitStateService } from '../services/unit-state.service';
+import { MediaPlayerService } from '../services/media-player.service';
+import { ValidationService } from '../services/validation.service';
 
 @Directive({
   selector: '[aspectUnitState]'
@@ -24,14 +24,15 @@ export class UnitStateDirective implements OnInit, OnDestroy {
   ) {}
 
   ngOnInit(): void {
-    this.mediaPlayerService.mediaStatusChanged
-      .pipe(takeUntil(this.ngUnsubscribe))
-      .subscribe((): void => this.sendVopStateChangedNotification());
-    this.unitStateService.presentedPageAdded
-      .pipe(takeUntil(this.ngUnsubscribe))
-      .subscribe((): void => this.sendVopStateChangedNotification());
-    this.unitStateService.elementCodeChanged
-      .pipe(takeUntil(this.ngUnsubscribe))
+    merge(
+      this.mediaPlayerService.mediaStatusChanged,
+      this.unitStateService.pagePresented,
+      this.unitStateService.elementCodeChanged
+    )
+      .pipe(
+        debounceTime(500),
+        takeUntil(this.ngUnsubscribe)
+      )
       .subscribe((): void => this.sendVopStateChangedNotification());
   }
 
diff --git a/projects/player/src/app/services/element-model-element-code-mapping.service.spec.ts b/projects/player/src/app/services/element-model-element-code-mapping.service.spec.ts
index 95b71b2495f5e4ffdc6c7f4f1acdb029b131ead1..b22e66659f2f8d1170302871c2c977688d946abb 100644
--- a/projects/player/src/app/services/element-model-element-code-mapping.service.spec.ts
+++ b/projects/player/src/app/services/element-model-element-code-mapping.service.spec.ts
@@ -1,5 +1,4 @@
 import { TestBed } from '@angular/core/testing';
-import { ElementModelElementCodeMappingService } from './element-model-element-code-mapping.service';
 import * as dropList_130 from 'test-data/element-models/drop-list_130.json';
 import * as dropListSimple_131 from 'test-data/element-models/drop-list-simple_131.json';
 import * as textField_130 from 'test-data/element-models/text-field_130.json';
@@ -33,6 +32,7 @@ import { RadioButtonGroupComplexElement } from 'common/models/elements/input-ele
 import { LikertRowElement } from 'common/models/elements/compound-elements/likert/likert-row';
 import { ToggleButtonElement } from 'common/models/elements/compound-elements/cloze/cloze-child-elements/toggle-button';
 import { DragNDropValueObject } from 'common/models/elements/element';
+import { ElementModelElementCodeMappingService } from './element-model-element-code-mapping.service';
 
 describe('ElementModelElementCodeMappingService', () => {
   let service: ElementModelElementCodeMappingService;
@@ -50,26 +50,26 @@ describe('ElementModelElementCodeMappingService', () => {
   it('should map the value of a drop-list elementModel to its elementCode value', () => {
     const dragNDropValueObjects: DragNDropValueObject[] = JSON.parse(JSON.stringify(dragNDropValues_01_130)).default;
     expect(service.mapToElementCodeValue(dragNDropValueObjects, 'drop-list'))
-      .toEqual( ['value_1', 'value_2', 'value_3']);
+      .toEqual(['value_1', 'value_2', 'value_3']);
   });
 
   it('should map the value of a drop-list-simple elementModel to its elementCode value', () => {
     const dragNDropValueObjects: DragNDropValueObject[] = JSON.parse(JSON.stringify(dragNDropValues_01_130)).default;
     expect(service.mapToElementCodeValue(dragNDropValueObjects, 'drop-list-simple'))
-      .toEqual( ['value_1', 'value_2', 'value_3']);
+      .toEqual(['value_1', 'value_2', 'value_3']);
   });
 
   it('should map the value of a text elementModel to its elementCode value', () => {
     const textValue =
       'Lorem <aspect-marked style="background-color: rgb(249, 248, 113);">ipsum</aspect-marked> dolor sit amet';
     expect(service.mapToElementCodeValue(textValue, 'text'))
-      .toEqual( ['6-11-#f9f871']);
+      .toEqual(['6-11-#f9f871']);
   });
 
   it('should map the value of a text elementModel to its elementCode value - empty Array', () => {
     const textValue = 'Lorem dolor sit amet';
     expect(service.mapToElementCodeValue(textValue, 'text'))
-      .toEqual( []);
+      .toEqual([]);
   });
 
   it('should map the value of a audio elementModel to its elementCode value', () => {
@@ -99,7 +99,6 @@ describe('ElementModelElementCodeMappingService', () => {
       .toBe(null);
   });
 
-
   it('should map the value of a radio-group-images elementModel to its elementCode value', () => {
     for (let i = 0; i < 10; i++) {
       expect(service.mapToElementCodeValue(i, 'radio-group-images'))
@@ -151,82 +150,93 @@ describe('ElementModelElementCodeMappingService', () => {
   it('should map the value of a text-field elementModel to its elementCode value', () => {
     const textFieldValue = 'TEST';
     expect(service.mapToElementCodeValue(textFieldValue, 'text-field'))
-      .toEqual( 'TEST');
+      .toEqual('TEST');
   });
 
   it('should map the value of a text-field elementModel to its elementCode value', () => {
     const textFieldValue = null;
     expect(service.mapToElementCodeValue(textFieldValue, 'text-field'))
-      .toEqual( null);
+      .toEqual(null);
   });
 
   it('should map the value of a text-field-simple elementModel to its elementCode value', () => {
     const textFieldValue = 'TEST';
     expect(service.mapToElementCodeValue(textFieldValue, 'text-field-simple'))
-      .toEqual( 'TEST');
+      .toEqual('TEST');
   });
 
   it('should map the value of a text-field-simple elementModel to its elementCode value', () => {
     const textFieldValue = null;
     expect(service.mapToElementCodeValue(textFieldValue, 'text-field-simple'))
-      .toEqual( null);
+      .toEqual(null);
   });
 
   it('should map the value of a spell-correct elementModel to its elementCode value', () => {
     const spellCorrectValue = 'TEST';
     expect(service.mapToElementCodeValue(spellCorrectValue, 'spell-correct'))
-      .toEqual( 'TEST');
+      .toEqual('TEST');
   });
 
   it('should map the value of a spell-correct elementModel to its elementCode value', () => {
     const spellCorrectValue = null;
     expect(service.mapToElementCodeValue(spellCorrectValue, 'spell-correct'))
-      .toEqual( null);
+      .toEqual(null);
   });
 
   it('should map the value of a text-area elementModel to its elementCode value', () => {
     const textAreaValue = 'TEST';
     expect(service.mapToElementCodeValue(textAreaValue, 'text-area'))
-      .toEqual( 'TEST');
+      .toEqual('TEST');
   });
 
   it('should map the value of a text-area elementModel to its elementCode value', () => {
     const textAreaValue = null;
     expect(service.mapToElementCodeValue(textAreaValue, 'text-area'))
-      .toEqual( null);
+      .toEqual(null);
   });
 
-
   // mapToElementValue
 
   it('should map an elementCode value to drop-list elementModel value', () => {
-    service.dragNDropValueObjects =  [
+    service.dragNDropValueObjects = [
       {
-        'stringValue': 'a',
-        'id': 'value_1'
+        text: 'a',
+        id: 'value_1',
+        imgSrc: null,
+        imgPosition: 'above'
       },
       {
-        'stringValue': 'b',
-        'id': 'value_2'
+        text: 'b',
+        id: 'value_2',
+        imgSrc: null,
+        imgPosition: 'above'
       },
       {
-        'stringValue': 'c',
-        'id': 'value_3'
+        text: 'c',
+        id: 'value_3',
+        imgSrc: null,
+        imgPosition: 'above'
       },
       {
-        'stringValue': 'd',
-        'id': 'value_4'
+        text: 'd',
+        id: 'value_4',
+        imgSrc: null,
+        imgPosition: 'above'
       },
       {
-        'stringValue': 'e',
-        'id': 'value_5'
+        text: 'e',
+        id: 'value_5',
+        imgSrc: null,
+        imgPosition: 'above'
       }
     ];
     const elementModel: DropListElement = JSON.parse(JSON.stringify(dropList_130));
-    const expectedValue = [
+    const expectedValue: DragNDropValueObject[] = [
       {
-        'stringValue': 'e',
-        'id': 'value_5'
+        text: 'e',
+        id: 'value_5',
+        imgSrc: null,
+        imgPosition: 'above'
       }
     ];
     expect(service.mapToElementModelValue(['value_5'], elementModel))
@@ -234,33 +244,45 @@ describe('ElementModelElementCodeMappingService', () => {
   });
 
   it('should map an elementCode value to drop-list elementModel value', () => {
-    service.dragNDropValueObjects =  [
+    service.dragNDropValueObjects = [
       {
-        'stringValue': 'a',
-        'id': 'value_1'
+        text: 'a',
+        id: 'value_1',
+        imgSrc: null,
+        imgPosition: 'above'
       },
       {
-        'stringValue': 'b',
-        'id': 'value_2'
+        text: 'b',
+        id: 'value_2',
+        imgSrc: null,
+        imgPosition: 'above'
       },
       {
-        'stringValue': 'c',
-        'id': 'value_3'
+        text: 'c',
+        id: 'value_3',
+        imgSrc: null,
+        imgPosition: 'above'
       },
       {
-        'stringValue': 'd',
-        'id': 'value_4'
+        text: 'd',
+        id: 'value_4',
+        imgSrc: null,
+        imgPosition: 'above'
       },
       {
-        'stringValue': 'e',
-        'id': 'value_5'
+        text: 'e',
+        id: 'value_5',
+        imgSrc: null,
+        imgPosition: 'above'
       }
     ];
     const elementModel: DropListElement = JSON.parse(JSON.stringify(dropList_130));
-    const expectedValue = [
+    const expectedValue: DragNDropValueObject[] = [
       {
-        'stringValue': 'e',
-        'id': 'value_5'
+        text: 'e',
+        id: 'value_5',
+        imgSrc: null,
+        imgPosition: 'above'
       }
     ];
     expect(service.mapToElementModelValue(['value_5'], elementModel))
@@ -268,26 +290,36 @@ describe('ElementModelElementCodeMappingService', () => {
   });
 
   it('should not map but return the drop-list-simple elementModel value', () => {
-    service.dragNDropValueObjects =  [
+    service.dragNDropValueObjects = [
       {
-        'stringValue': 'a',
-        'id': 'value_1'
+        text: 'a',
+        id: 'value_1',
+        imgSrc: null,
+        imgPosition: 'above'
       },
       {
-        'stringValue': 'b',
-        'id': 'value_2'
+        text: 'b',
+        id: 'value_2',
+        imgSrc: null,
+        imgPosition: 'above'
       },
       {
-        'stringValue': 'c',
-        'id': 'value_3'
+        text: 'c',
+        id: 'value_3',
+        imgSrc: null,
+        imgPosition: 'above'
       },
       {
-        'stringValue': 'd',
-        'id': 'value_4'
+        text: 'd',
+        id: 'value_4',
+        imgSrc: null,
+        imgPosition: 'above'
       },
       {
-        'stringValue': 'e',
-        'id': 'value_5'
+        text: 'e',
+        id: 'value_5',
+        imgSrc: null,
+        imgPosition: 'above'
       }
     ];
     const elementModel: DropListSimpleElement = JSON.parse(JSON.stringify(dropListSimple_131));
@@ -314,14 +346,14 @@ describe('ElementModelElementCodeMappingService', () => {
   it('should map an elementCode value to drop-list-simple elementModel value - an empty array', () => {
     service.dragNDropValueObjects = JSON.parse(JSON.stringify(dragNDropValues_01_130)).default;
     const elementModel: DropListElement = JSON.parse(JSON.stringify(dropList_130));
-    expect(service.mapToElementModelValue([], elementModel ))
+    expect(service.mapToElementModelValue([], elementModel))
       .toEqual([]);
   });
 
   it('should map an elementCode value to drop-list elementModel value - an empty array', () => {
     service.dragNDropValueObjects = JSON.parse(JSON.stringify(dragNDropValues_01_130)).default;
     const elementModel: DropListSimpleElement = JSON.parse(JSON.stringify(dropListSimple_131));
-    expect(service.mapToElementModelValue([], elementModel ))
+    expect(service.mapToElementModelValue([], elementModel))
       .toEqual([]);
   });
 
@@ -347,121 +379,121 @@ describe('ElementModelElementCodeMappingService', () => {
 
   it('should map an elementCode value to audio elementModel value', () => {
     const elementModel: AudioElement = JSON.parse(JSON.stringify(audio_130));
-    expect(service.mapToElementModelValue( 2, elementModel))
+    expect(service.mapToElementModelValue(2, elementModel))
       .toEqual(2);
   });
 
   it('should not map but return the audio elementModel value (player.playbackTime)', () => {
     const elementModel: AudioElement = JSON.parse(JSON.stringify(audio_130));
-    expect(service.mapToElementModelValue( undefined, elementModel))
+    expect(service.mapToElementModelValue(undefined, elementModel))
       .toEqual(0);
   });
 
   it('should map an elementCode value to image elementModel value', () => {
     const elementModel: ImageElement = JSON.parse(JSON.stringify(image_130));
-    expect(service.mapToElementModelValue( true, elementModel))
+    expect(service.mapToElementModelValue(true, elementModel))
       .toEqual(true);
   });
 
   it('should not map but return the image elementModel value (magnifierUsed)', () => {
     const elementModel: ImageElement = JSON.parse(JSON.stringify(image_130));
-    expect(service.mapToElementModelValue( undefined, elementModel))
+    expect(service.mapToElementModelValue(undefined, elementModel))
       .toEqual(false);
   });
 
   it('should map an elementCode value to text-field elementModel value', () => {
     const elementModel: TextFieldElement = JSON.parse(JSON.stringify(textField_130));
-    expect(service.mapToElementModelValue( 'TEST', elementModel))
+    expect(service.mapToElementModelValue('TEST', elementModel))
       .toEqual('TEST');
   });
 
   it('should not map but return the text-field elementModel value', () => {
     const elementModel: TextFieldElement = JSON.parse(JSON.stringify(textField_130));
-    expect(service.mapToElementModelValue( undefined, elementModel))
+    expect(service.mapToElementModelValue(undefined, elementModel))
       .toEqual(null);
   });
 
   it('should map an elementCode value to text-field-simple elementModel value', () => {
     const elementModel: TextFieldSimpleElement = JSON.parse(JSON.stringify(textFieldSimple_131));
-    expect(service.mapToElementModelValue( 'TEST', elementModel))
+    expect(service.mapToElementModelValue('TEST', elementModel))
       .toEqual('TEST');
   });
 
   it('should not map but return the text-field-simple elementModel value', () => {
     const elementModel: TextFieldSimpleElement = JSON.parse(JSON.stringify(textFieldSimple_131));
-    expect(service.mapToElementModelValue( undefined, elementModel))
+    expect(service.mapToElementModelValue(undefined, elementModel))
       .toEqual(null);
   });
 
   it('should map an elementCode value to text-area elementModel value', () => {
     const elementModel: TextAreaElement = JSON.parse(JSON.stringify(textArea_130));
-    expect(service.mapToElementModelValue( 'TEST', elementModel))
+    expect(service.mapToElementModelValue('TEST', elementModel))
       .toEqual('TEST');
   });
 
   it('should not map but return the text-area elementModel value', () => {
     const elementModel: TextAreaElement = JSON.parse(JSON.stringify(textArea_130));
-    expect(service.mapToElementModelValue( undefined, elementModel))
+    expect(service.mapToElementModelValue(undefined, elementModel))
       .toEqual(null);
   });
 
   it('should map an elementCode value to spell-correct elementModel value', () => {
     const elementModel: SpellCorrectElement = JSON.parse(JSON.stringify(spellCorrect_130));
-    expect(service.mapToElementModelValue( 'TEST', elementModel))
+    expect(service.mapToElementModelValue('TEST', elementModel))
       .toEqual('TEST');
   });
 
   it('should not map but return the spell-correct elementModel value', () => {
     const elementModel: SpellCorrectElement = JSON.parse(JSON.stringify(spellCorrect_130));
-    expect(service.mapToElementModelValue( undefined, elementModel))
+    expect(service.mapToElementModelValue(undefined, elementModel))
       .toEqual(null);
   });
 
   it('should map an elementCode value to radio elementModel value', () => {
     const elementModel: RadioButtonGroupElement = JSON.parse(JSON.stringify(radio_130));
-    expect(service.mapToElementModelValue( 1, elementModel))
+    expect(service.mapToElementModelValue(1, elementModel))
       .toEqual(0);
   });
 
   it('should not map but return the radio elementModel value', () => {
     const elementModel: RadioButtonGroupElement = JSON.parse(JSON.stringify(radio_130));
-    expect(service.mapToElementModelValue( undefined, elementModel))
+    expect(service.mapToElementModelValue(undefined, elementModel))
       .toEqual(null);
   });
 
   it('should map an elementCode value to radio-group-images elementModel value', () => {
     const elementModel: RadioButtonGroupComplexElement = JSON.parse(JSON.stringify(radioGroupImages_130));
-    expect(service.mapToElementModelValue( 2, elementModel))
+    expect(service.mapToElementModelValue(2, elementModel))
       .toEqual(1);
   });
 
   it('should not map but return the radio-group-images elementModel value', () => {
     const elementModel: RadioButtonGroupComplexElement = JSON.parse(JSON.stringify(radioGroupImages_130));
-    expect(service.mapToElementModelValue( undefined, elementModel))
+    expect(service.mapToElementModelValue(undefined, elementModel))
       .toEqual(null);
   });
 
   it('should map an elementCode value to likert-row elementModel value', () => {
     const elementModel: LikertRowElement = JSON.parse(JSON.stringify(likertRow_130));
-    expect(service.mapToElementModelValue( 3, elementModel))
+    expect(service.mapToElementModelValue(3, elementModel))
       .toEqual(2);
   });
 
   it('should not map but return the likert-row elementModel value', () => {
     const elementModel: LikertRowElement = JSON.parse(JSON.stringify(likertRow_130));
-    expect(service.mapToElementModelValue( undefined, elementModel))
+    expect(service.mapToElementModelValue(undefined, elementModel))
       .toEqual(null);
   });
 
   it('should map an elementCode value to toggle-button elementModel value', () => {
     const elementModel: ToggleButtonElement = JSON.parse(JSON.stringify(toggleButton_130));
-    expect(service.mapToElementModelValue( 1, elementModel))
+    expect(service.mapToElementModelValue(1, elementModel))
       .toEqual(0);
   });
 
   it('should not map but return the toggle-button elementModel value', () => {
     const elementModel: ToggleButtonElement = JSON.parse(JSON.stringify(toggleButton_130));
-    expect(service.mapToElementModelValue( undefined, elementModel))
+    expect(service.mapToElementModelValue(undefined, elementModel))
       .toEqual(null);
   });
 });
diff --git a/projects/player/src/app/services/keyboard.service.spec.ts b/projects/player/src/app/services/keyboard.service.spec.ts
index 9dd1c0d8e7545e64d76fad624b7a4874884dbea5..e0f2c71896a527e6f02c0fa90a2de7992c99c3a0 100644
--- a/projects/player/src/app/services/keyboard.service.spec.ts
+++ b/projects/player/src/app/services/keyboard.service.spec.ts
@@ -1,7 +1,6 @@
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
 import { KeyInputModule } from 'player/modules/key-input/key-input.module';
-import { KeyboardService } from './keyboard.service';
 import { TextFieldComponent } from 'common/components/input-elements/text-field.component';
 import {
   TextFieldSimpleComponent
@@ -13,6 +12,7 @@ import * as textField_130 from 'test-data/element-models/text-field_130.json';
 import * as textFieldSimple_131 from 'test-data/element-models/text-field-simple_131.json';
 import * as textArea_130 from 'test-data/element-models/text-area_130.json';
 import * as spellCorrect_130 from 'test-data/element-models/spell-correct_130.json';
+import { KeyboardService } from './keyboard.service';
 
 describe('KeyboardService', () => {
   let service: KeyboardService;
@@ -76,7 +76,6 @@ describe('KeyboardService', () => {
     expect(service.isOpen).toBeFalse();
   });
 
-
   it('should not toggle keyboard to open', () => {
     const element = textFieldComponent.domElement.querySelector('input') as HTMLInputElement;
     const input = { inputElement: element, focused: true };
@@ -84,7 +83,6 @@ describe('KeyboardService', () => {
     expect(service.isOpen).toBeFalse();
   });
 
-
   it('should set the inputElement of the service', () => {
     const element = textFieldComponent.domElement.querySelector('input') as HTMLInputElement;
     const input = { inputElement: element, focused: true };
@@ -111,7 +109,6 @@ describe('KeyboardService', () => {
     expect(service.inputElement.value).toEqual('n!');
   });
 
-
   it('enter "!" should replace the inputElement.value of the service with to "!"', () => {
     const element = textFieldComponent.domElement.querySelector('input') as HTMLInputElement;
     const input = { inputElement: element, focused: true };
@@ -178,7 +175,6 @@ describe('KeyboardService', () => {
     expect(service.isOpen).toBeTruthy();
   });
 
-
   it('should toggle keyboard to close', () => {
     service.isOpen = true;
     const element = textFieldSimpleComponent.domElement.querySelector('input') as HTMLInputElement;
@@ -187,7 +183,6 @@ describe('KeyboardService', () => {
     expect(service.isOpen).toBeFalse();
   });
 
-
   it('should not toggle keyboard to open', () => {
     const element = textFieldSimpleComponent.domElement.querySelector('input') as HTMLInputElement;
     const input = { inputElement: element, focused: true };
@@ -195,7 +190,6 @@ describe('KeyboardService', () => {
     expect(service.isOpen).toBeFalse();
   });
 
-
   it('should set the inputElement of the service', () => {
     const element = textFieldSimpleComponent.domElement.querySelector('input') as HTMLInputElement;
     const input = { inputElement: element, focused: true };
@@ -296,7 +290,6 @@ describe('KeyboardService', () => {
     expect(service.isOpen).toBeFalse();
   });
 
-
   it('should not toggle keyboard to open', () => {
     const element = textAreaComponent.domElement.querySelector('textarea') as HTMLTextAreaElement;
     const input = { inputElement: element, focused: true };
@@ -304,7 +297,6 @@ describe('KeyboardService', () => {
     expect(service.isOpen).toBeFalse();
   });
 
-
   it('should set the inputElement of the service', () => {
     const element = textAreaComponent.domElement.querySelector('textarea') as HTMLTextAreaElement;
     const input = { inputElement: element, focused: true };
@@ -405,7 +397,6 @@ describe('KeyboardService', () => {
     expect(service.isOpen).toBeFalse();
   });
 
-
   it('should not toggle keyboard to open', () => {
     const element = spellCorrectComponent.domElement.querySelector('input') as HTMLInputElement;
     const input = { inputElement: element, focused: true };
@@ -413,7 +404,6 @@ describe('KeyboardService', () => {
     expect(service.isOpen).toBeFalse();
   });
 
-
   it('should set the inputElement of the service', () => {
     const element = spellCorrectComponent.domElement.querySelector('input') as HTMLInputElement;
     const input = { inputElement: element, focused: true };
diff --git a/projects/player/src/app/services/keypad.service.spec.ts b/projects/player/src/app/services/keypad.service.spec.ts
index 5ccd6deb555562aa4503d705199154db9617324b..e68e496706ef56dc2f72d1189f1270274cb332a8 100644
--- a/projects/player/src/app/services/keypad.service.spec.ts
+++ b/projects/player/src/app/services/keypad.service.spec.ts
@@ -1,7 +1,6 @@
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
 import { KeyInputModule } from 'player/modules/key-input/key-input.module';
-import { KeypadService } from './keypad.service';
 import { TextFieldComponent } from 'common/components/input-elements/text-field.component';
 import { TextAreaComponent } from 'common/components/input-elements/text-area.component';
 import {
@@ -13,7 +12,7 @@ import * as textField_130 from 'test-data/element-models/text-field_130.json';
 import * as textFieldSimple_131 from 'test-data/element-models/text-field-simple_131.json';
 import * as textArea_130 from 'test-data/element-models/text-area_130.json';
 import * as spellCorrect_130 from 'test-data/element-models/spell-correct_130.json';
-
+import { KeypadService } from './keypad.service';
 
 describe('KeypadService', () => {
   let service: KeypadService;
@@ -69,7 +68,6 @@ describe('KeypadService', () => {
     expect(service.isOpen).toBeTruthy();
   });
 
-
   it('should toggle keypad to close', () => {
     service.isOpen = true;
     const element = textFieldComponent.domElement.querySelector('input') as HTMLInputElement;
@@ -78,7 +76,6 @@ describe('KeypadService', () => {
     expect(service.isOpen).toBeFalse();
   });
 
-
   it('should set the inputElement of the service', () => {
     const element = textFieldComponent.domElement.querySelector('input') as HTMLInputElement;
     const input = { inputElement: element, focused: true };
@@ -178,7 +175,6 @@ describe('KeypadService', () => {
     expect(service.isOpen).toBeTruthy();
   });
 
-
   it('should toggle keypad to close', () => {
     service.isOpen = true;
     const element = textFieldSimpleComponent.domElement.querySelector('input') as HTMLInputElement;
@@ -393,7 +389,6 @@ describe('KeypadService', () => {
     expect(service.isOpen).toBeTruthy();
   });
 
-
   it('should toggle keypad to close', () => {
     service.isOpen = true;
     const element = spellCorrectComponent.domElement.querySelector('input') as HTMLInputElement;
diff --git a/projects/player/src/app/services/media-player.service.spec.ts b/projects/player/src/app/services/media-player.service.spec.ts
index 57c27cabb92773e68384568017047aec231c56c9..ca5e291e7331cc71e80878bc6cb586d1c16edd2a 100644
--- a/projects/player/src/app/services/media-player.service.spec.ts
+++ b/projects/player/src/app/services/media-player.service.spec.ts
@@ -1,7 +1,6 @@
 import { TestBed } from '@angular/core/testing';
 import { MediaPlayerService } from './media-player.service';
 
-
 describe('MediaPlayerService', () => {
   let service: MediaPlayerService;
   beforeEach(() => {
@@ -17,7 +16,7 @@ describe('MediaPlayerService', () => {
     const mediaId = 'audio_1';
     service.registerMediaElement(mediaId, false);
     service.mediaStatusChanged
-      .subscribe( id => {
+      .subscribe(id => {
         expect(id).toEqual(mediaId);
         done();
       });
@@ -29,7 +28,7 @@ describe('MediaPlayerService', () => {
     service.registerMediaElement(mediaId, false);
     service.registerMediaElement('audio_2', false);
     service.mediaStatusChanged
-      .subscribe( id => {
+      .subscribe(id => {
         expect(id).toEqual(mediaId);
         done();
       });
@@ -41,7 +40,7 @@ describe('MediaPlayerService', () => {
     service.registerMediaElement(mediaId, false);
     service.registerMediaElement('audio_2', false);
     service.mediaStatusChanged
-      .subscribe( id => {
+      .subscribe(id => {
         expect(id).not.toEqual(mediaId);
         done();
       });
@@ -77,7 +76,7 @@ describe('MediaPlayerService', () => {
   it('actualPlayingMediaId should be audio_1', done => {
     const mediaId = 'audio_1';
     service.actualPlayingId
-      .subscribe( id => {
+      .subscribe(id => {
         expect(id).toEqual(mediaId);
         done();
       });
@@ -87,7 +86,7 @@ describe('MediaPlayerService', () => {
   it('pageIndex should not be audio_1', done => {
     const mediaId = 'audio_1';
     service.actualPlayingId
-      .subscribe( id => {
+      .subscribe(id => {
         expect(id).not.toEqual(mediaId);
         done();
       });
diff --git a/projects/player/src/app/services/navigation.service.spec.ts b/projects/player/src/app/services/navigation.service.spec.ts
index cba9d2f721f4e19efe56f8c4b15dac89ed818910..81fa74965e4aec819bd16495973b5dbc8e7bac39 100644
--- a/projects/player/src/app/services/navigation.service.spec.ts
+++ b/projects/player/src/app/services/navigation.service.spec.ts
@@ -14,7 +14,7 @@ describe('NavigationService', () => {
 
   it('pageIndex should be 2', done => {
     service.pageIndex
-      .subscribe( pageIndex => {
+      .subscribe(pageIndex => {
         expect(pageIndex).toEqual(2);
         done();
       });
@@ -23,7 +23,7 @@ describe('NavigationService', () => {
 
   it('pageIndex should not be 2', done => {
     service.pageIndex
-      .subscribe( pageIndex => {
+      .subscribe(pageIndex => {
         expect(pageIndex).not.toEqual(2);
         done();
       });
diff --git a/projects/player/src/app/services/text-marking.service.spec.ts b/projects/player/src/app/services/text-marking.service.spec.ts
index 641c75187487321909abc1ed24f6c93a8a2fc4eb..6b36d3e629cb3b80da681dabf9d15addf01a39a7 100644
--- a/projects/player/src/app/services/text-marking.service.spec.ts
+++ b/projects/player/src/app/services/text-marking.service.spec.ts
@@ -26,5 +26,4 @@ describe('TextMarkingService', () => {
     const markings = ['6-11-#f9f871'];
     expect(TextMarkingService.restoreMarkedTextIndices(markings, text)).toEqual(expectedText);
   });
-
 });
diff --git a/projects/player/src/app/services/unit-state.service.spec.ts b/projects/player/src/app/services/unit-state.service.spec.ts
index ce20e225b8a87afd5e242b467c80aa5f84e7b1df..863b6dbdf1f0a1e262fcef7f045dd4a74e39cac0 100644
--- a/projects/player/src/app/services/unit-state.service.spec.ts
+++ b/projects/player/src/app/services/unit-state.service.spec.ts
@@ -1,6 +1,6 @@
 import { TestBed } from '@angular/core/testing';
-import { UnitStateService } from './unit-state.service';
 import { ElementCode } from 'player/modules/verona/models/verona';
+import { UnitStateService } from './unit-state.service';
 
 describe('UnitStateService', () => {
   let service: UnitStateService;
@@ -14,16 +14,16 @@ describe('UnitStateService', () => {
   });
 
   it('should get element by id', () => {
-    const element1: ElementCode =  { id: 'element_1', status: 'DISPLAYED', value: 'TEST1' };
-    const element2: ElementCode =  { id: 'element_2', status: 'DISPLAYED', value: 'TEST2' };
-    service.elementCodes = [ element1, element2 ];
+    const element1: ElementCode = { id: 'element_1', status: 'DISPLAYED', value: 'TEST1' };
+    const element2: ElementCode = { id: 'element_2', status: 'DISPLAYED', value: 'TEST2' };
+    service.elementCodes = [element1, element2];
     expect(service.getElementCodeById('element_1')).toEqual(element1);
   });
 
   it('should return undefined for a not registered element id', () => {
-    const element1: ElementCode =  { id: 'element_1', status: 'DISPLAYED', value: 'TEST1' };
-    const element2: ElementCode =  { id: 'element_2', status: 'DISPLAYED', value: 'TEST2' };
-    service.elementCodes = [ element1, element2 ];
+    const element1: ElementCode = { id: 'element_1', status: 'DISPLAYED', value: 'TEST1' };
+    const element2: ElementCode = { id: 'element_2', status: 'DISPLAYED', value: 'TEST2' };
+    service.elementCodes = [element1, element2];
     expect(service.getElementCodeById('element_3')).toBeUndefined();
   });
 
@@ -31,13 +31,13 @@ describe('UnitStateService', () => {
     service.elementCodes = [];
     const element = document.createElement('div');
     service.registerElement('element', 'TEST', element, 1);
-    expect(service.elementCodes).toEqual([ { id: 'element', status: 'NOT_REACHED', value: 'TEST' } ]);
+    expect(service.elementCodes).toEqual([{ id: 'element', status: 'NOT_REACHED', value: 'TEST' }]);
   });
 
   it('elementCode of an element should change', done => {
     service.elementCodes = [{ id: 'element_1', status: 'NOT_REACHED', value: 'TEST1' }];
     service.elementCodeChanged
-      .subscribe( code => {
+      .subscribe(code => {
         expect(code.status).toEqual('DISPLAYED');
         done();
       });
@@ -47,11 +47,11 @@ describe('UnitStateService', () => {
   it('elementCode of an element should change', done => {
     service.elementCodes = [{ id: 'element_1', status: 'NOT_REACHED', value: 'TEST1' }];
     service.elementCodeChanged
-      .subscribe( code =>  {
+      .subscribe(code => {
         expect(code.status).toEqual('VALUE_CHANGED');
         expect(code.value).toEqual('NEU');
         done();
-      }) ;
+      });
     service.changeElementCodeValue({ id: 'element_1', value: 'NEU' });
   });
 
@@ -107,8 +107,8 @@ describe('UnitStateService', () => {
     service.elementCodes = [];
     const element = document.createElement('div');
     service.registerElement('element_1', 'TEST1', element, 1);
-    service.presentedPageAdded
-      .subscribe( index => {
+    service.pagePresented
+      .subscribe(index => {
         expect(index).toEqual(1);
         done();
       });
@@ -119,12 +119,11 @@ describe('UnitStateService', () => {
     service.elementCodes = [];
     const element = document.createElement('div');
     service.registerElement('element_1', 'TEST1', element, 1);
-    service.presentedPageAdded
-      .subscribe( index => {
+    service.pagePresented
+      .subscribe(index => {
         expect(index).toEqual(1);
         done();
       });
     service.changeElementCodeValue({ id: 'element_1', value: 'NEU' });
   });
-
 });
diff --git a/projects/player/src/app/services/unit-state.service.ts b/projects/player/src/app/services/unit-state.service.ts
index dd22bd12dbbf27cbde3b4b00bb820931fce701bd..33c7db353537cc09dd0b0bc58d8157562d477d09 100644
--- a/projects/player/src/app/services/unit-state.service.ts
+++ b/projects/player/src/app/services/unit-state.service.ts
@@ -4,16 +4,16 @@ import { DOCUMENT } from '@angular/common';
 import {
   Progress, StatusChangeElement, ElementCode, ElementCodeStatus, ElementCodeStatusValue
 } from 'player/modules/verona/models/verona';
-import { IntersectionDetector } from '../classes/intersection-detector';
 import { LogService } from 'player/modules/logging/services/log.service';
 import { InputElementValue, ValueChangeElement } from 'common/models/elements/element';
+import { IntersectionDetector } from '../classes/intersection-detector';
 
 @Injectable({
   providedIn: 'root'
 })
 export class UnitStateService {
   private _elementCodes: ElementCode[] = [];
-  private _presentedPageAdded = new Subject<number>();
+  private _pagePresented = new Subject<number>();
   private _elementCodeChanged = new Subject<ElementCode>();
   private presentedPages: number[] = [];
   private elementIdPageIndexMap: { [elementId: string]: number } = {};
@@ -40,8 +40,8 @@ export class UnitStateService {
     return this._elementCodeChanged.asObservable();
   }
 
-  get presentedPageAdded(): Observable<number> {
-    return this._presentedPageAdded.asObservable();
+  get pagePresented(): Observable<number> {
+    return this._pagePresented.asObservable();
   }
 
   get presentedPagesProgress(): Progress {
@@ -81,8 +81,10 @@ export class UnitStateService {
     this.intersectionDetector.observe(domElement, elementId);
     this.intersectionDetector.intersecting
       .subscribe((id: string) => {
-        this.changeElementCodeStatus({ id: id, status: 'DISPLAYED' });
-        this.intersectionDetector.unobserve(id);
+        if (elementId === id) {
+          this.changeElementCodeStatus({ id: id, status: 'DISPLAYED' });
+          this.intersectionDetector.unobserve(id);
+        }
       });
   }
 
@@ -115,7 +117,7 @@ export class UnitStateService {
   }
 
   private buildPresentedPages(): void {
-    const uniqPages = [...new Set( Object.values(this.elementIdPageIndexMap))];
+    const uniqPages = [...new Set(Object.values(this.elementIdPageIndexMap))];
     uniqPages.forEach(pageIndex => this
       .checkPresentedPageStatus(pageIndex));
   }
@@ -130,7 +132,7 @@ export class UnitStateService {
           ElementCodeStatusValue.DISPLAYED);
       if (notDisplayedElements.length === 0) {
         this.presentedPages.push(pageIndex);
-        this._presentedPageAdded.next(pageIndex);
+        this._pagePresented.next(pageIndex);
       }
     } else {
       LogService.warn(`player: page ${pageIndex} is already presented`);
@@ -144,11 +146,9 @@ export class UnitStateService {
       unitStateElementCode = { id: id, value: value, status: 'NOT_REACHED' };
       this.elementCodes.push(unitStateElementCode);
       this._elementCodeChanged.next(unitStateElementCode);
-    } else {
+    } else if (Object.keys(this.elementIdPageIndexMap).length === this.elementCodes.length) {
       // if all elements are registered, we can rebuild the presentedPages array
-      if (Object.keys(this.elementIdPageIndexMap).length === this.elementCodes.length) {
-        this.buildPresentedPages();
-      }
+      this.buildPresentedPages();
     }
     if (unitStateElementCode.status === 'NOT_REACHED') {
       this.addIntersectionDetection(id, domElement);
diff --git a/projects/player/src/app/services/validation.service.spec.ts b/projects/player/src/app/services/validation.service.spec.ts
index 7252c636c5e039a5bb65966e2816340aad4711c9..2fad00d2af24d612834fd971be4b71073cde18c7 100644
--- a/projects/player/src/app/services/validation.service.spec.ts
+++ b/projects/player/src/app/services/validation.service.spec.ts
@@ -1,6 +1,6 @@
 import { TestBed } from '@angular/core/testing';
-import { ValidationService } from './validation.service';
 import { FormControl } from '@angular/forms';
+import { ValidationService } from './validation.service';
 
 describe('ValidationService', () => {
   let service: ValidationService;
@@ -32,5 +32,4 @@ describe('ValidationService', () => {
     service.registerFormControl(new FormControl(''));
     expect(service.responseProgress).toEqual('some');
   });
-
 });
diff --git a/scripts/wrap_and_pack.js b/scripts/wrap_and_pack.js
index 27c94c5d70ad589ad56efda18ba7efced1e82781..6f8dcef68f4f15877eb2f7388c5002ad0016d7a8 100644
--- a/scripts/wrap_and_pack.js
+++ b/scripts/wrap_and_pack.js
@@ -1,19 +1,18 @@
 #!/usr/bin/env node
 
+// eslint-disable-next-line @typescript-eslint/no-var-requires
 const fs = require('fs');
-const childProcess = require('child_process');
+// eslint-disable-next-line @typescript-eslint/no-var-requires
+const execSync = require('child_process').execSync;
 
 const packageName = process.argv[2];
 const packageVersion = process.argv[3];
 const wrapperPath = process.argv[4];
 
-childProcess.fork('node_modules/iqb-dev-components/src/js_css_packer.js',
-  ['dist', packageName, 'dist']);
-
+execSync(`node node_modules/iqb-dev-components/src/js_css_packer.js dist ${packageName} dist`);
 const fileContent = fs.readFileSync(wrapperPath, 'utf8').toString()
   .replace(/version-placeholder/g, packageVersion);
 fs.writeFileSync('dist/index.html', fileContent, 'utf8');
 
 const targetFileName = `verona-${packageName}-aspect-${packageVersion}.html`;
-childProcess.fork('node_modules/iqb-dev-components/src/distpacker.js',
-['dist', targetFileName, packageName]);
+execSync(`node node_modules/iqb-dev-components/src/distpacker.js dist ${targetFileName} ${packageName}`);