You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by bo...@apache.org on 2021/02/24 09:52:54 UTC

[myfaces-tobago] 01/03: build(npm): fix production mode resources and source maps switch to eslint rollup is creating the tobago.js from typescript source directly

This is an automated email from the ASF dual-hosted git repository.

bommel pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/myfaces-tobago.git

commit 049972f49a809361f3aaa3f57c8ceb528e49edd7
Author: Bernd Bohmann <bo...@apache.org>
AuthorDate: Tue Feb 23 11:12:42 2021 +0100

    build(npm): fix production mode resources and source maps
    switch to eslint
    rollup is creating the tobago.js from typescript source directly
---
 .../internal/renderkit/renderer/PageRenderer.java  |     5 +-
 tobago-example/pom.xml                             |     4 +-
 tobago-example/tobago-example-demo/pom.xml         |    10 -
 tobago-theme/pom.xml                               |     2 +
 .../tobago-theme-standard/npm/.eslintignore        |     4 +
 .../tobago-theme-standard/npm/.eslintrc.js         |    68 +
 .../npm/dist/css/font-awesome.min.css              |     4 +
 .../npm/dist/js/tobago-all.js.map                  |     2 +-
 .../npm/dist/js/tobago-bar.js.map                  |     2 +-
 .../npm/dist/js/tobago-command.js.map              |     2 +-
 .../npm/dist/js/tobago-config.js.map               |     2 +-
 .../npm/dist/js/tobago-date.js.map                 |     2 +-
 .../npm/dist/js/tobago-dropdown.js.map             |     2 +-
 .../npm/dist/js/tobago-example.js                  |    27 -
 .../npm/dist/js/tobago-example.js.map              |     1 -
 .../npm/dist/js/tobago-file.js.map                 |     2 +-
 .../npm/dist/js/tobago-focus.js.map                |     2 +-
 .../npm/dist/js/tobago-footer.js.map               |     2 +-
 .../npm/dist/js/tobago-in.js.map                   |     2 +-
 .../npm/dist/js/tobago-listener.js.map             |     2 +-
 .../npm/dist/js/tobago-messages.js.map             |     2 +-
 .../npm/dist/js/tobago-overlay.js.map              |     2 +-
 .../npm/dist/js/tobago-page.js.map                 |     2 +-
 .../npm/dist/js/tobago-panel.js.map                |     2 +-
 .../npm/dist/js/tobago-polyfill.js.map             |     2 +-
 .../npm/dist/js/tobago-popover.js.map              |     2 +-
 .../npm/dist/js/tobago-popup.js.map                |     2 +-
 .../npm/dist/js/tobago-range.js.map                |     2 +-
 .../npm/dist/js/tobago-reload.js.map               |     2 +-
 .../npm/dist/js/tobago-scroll.js.map               |     2 +-
 .../dist/js/tobago-select-boolean-checkbox.js.map  |     2 +-
 .../dist/js/tobago-select-boolean-toggle.js.map    |     2 +-
 .../npm/dist/js/tobago-select-many-checkbox.js.map |     2 +-
 .../npm/dist/js/tobago-select-many-listbox.js.map  |     2 +-
 .../npm/dist/js/tobago-select-many-shuttle.js.map  |     2 +-
 .../npm/dist/js/tobago-select-one-choice.js.map    |     2 +-
 .../npm/dist/js/tobago-select-one-listbox.js.map   |     2 +-
 .../npm/dist/js/tobago-select-one-radio.js.map     |     2 +-
 .../npm/dist/js/tobago-selectable.js.map           |     2 +-
 .../npm/dist/js/tobago-sheet.js.map                |     2 +-
 .../npm/dist/js/tobago-split-layout.js.map         |     2 +-
 .../npm/dist/js/tobago-stars.js.map                |     2 +-
 .../npm/dist/js/tobago-suggest.js.map              |     2 +-
 .../npm/dist/js/tobago-tab.js.map                  |     2 +-
 .../npm/dist/js/tobago-textarea.js.map             |     2 +-
 .../npm/dist/js/tobago-tree-listbox.js.map         |     2 +-
 .../npm/dist/js/tobago-tree-node.js.map            |     2 +-
 .../npm/dist/js/tobago-tree-select.js.map          |     2 +-
 .../npm/dist/js/tobago-tree.js.map                 |     2 +-
 .../npm/dist/js/tobago-utils.js.map                |     2 +-
 .../tobago-theme-standard/npm/dist/js/tobago.js    | 24310 +++++++++----------
 .../npm/dist/js/tobago.js.map                      |     2 +-
 .../npm/dist/js/tobago.min.js                      |     8 +
 .../npm/dist/js/tobago.min.js.map                  |     1 +
 .../tobago-theme-standard/npm/jest.config.js       |     8 +-
 .../tobago-theme-standard/npm/package-lock.json    |   396 +-
 .../tobago-theme-standard/npm/package.json         |    15 +-
 .../tobago-theme-standard/npm/rollup.config.js     |    34 +-
 .../{tsconfig.json => tsconfig.development.json}   |     9 +-
 .../tobago-theme-standard/npm/tsconfig.json        |     7 +-
 .../{tsconfig.json => tsconfig.production.json}    |     9 +-
 tobago-theme/tobago-theme-standard/npm/tslint.json |    20 -
 tobago-theme/tobago-theme-standard/pom.xml         |     6 +-
 .../src/main/resources/META-INF/tobago-config.xml  |    12 +-
 64 files changed, 12611 insertions(+), 12433 deletions(-)

diff --git a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PageRenderer.java b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PageRenderer.java
index b69201c..9acab05 100644
--- a/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PageRenderer.java
+++ b/tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/PageRenderer.java
@@ -98,9 +98,6 @@ public class PageRenderer<T extends AbstractUIPage> extends RendererBase<T> {
     }
   }
 
-//  @Inject // fixme
-  private ProjectStage projectStage;
-
   @Override
   public void encodeBeginInternal(final FacesContext facesContext, final T component) throws IOException {
 
@@ -161,7 +158,7 @@ public class PageRenderer<T extends AbstractUIPage> extends RendererBase<T> {
     }
 
     final String clientId = component.getClientId(facesContext);
-    final boolean productionMode = projectStage == ProjectStage.Production;
+    final boolean productionMode = facesContext.isProjectStage(ProjectStage.Production);
     final Markup markup = component.getMarkup();
     final TobagoClass spread = markup != null && markup.contains(Markup.SPREAD) ? TobagoClass.SPREAD : null;
     final String title = component.getLabel();
diff --git a/tobago-example/pom.xml b/tobago-example/pom.xml
index d2a320f..37f7995 100644
--- a/tobago-example/pom.xml
+++ b/tobago-example/pom.xml
@@ -420,11 +420,11 @@
           <scope>compile</scope>
         </dependency>
         <!-- this enables the development mode -->
-        <dependency>
+        <!--dependency>
           <groupId>org.apache.myfaces.tobago</groupId>
           <artifactId>tobago-config-dev</artifactId>
           <version>${tobago.version}</version>
-        </dependency>
+        </dependency-->
       </dependencies>
     </profile>
 
diff --git a/tobago-example/tobago-example-demo/pom.xml b/tobago-example/tobago-example-demo/pom.xml
index 66bb13a..d47fff1 100644
--- a/tobago-example/tobago-example-demo/pom.xml
+++ b/tobago-example/tobago-example-demo/pom.xml
@@ -199,16 +199,6 @@
 
   <dependencies>
 
-    <!-- xxx remove me before release !!! -->
-    <!-- xxx this enables the development mode -->
-    <!-- xxx currently the production mode is not working.... -->
-    <dependency>
-      <groupId>org.apache.myfaces.tobago</groupId>
-      <artifactId>tobago-config-dev</artifactId>
-      <version>${tobago.version}</version>
-    </dependency>
-    <!-- xxx remove me before release !!! -->
-
     <!-- Tobago -->
     <dependency>
       <groupId>org.apache.myfaces.test</groupId>
diff --git a/tobago-theme/pom.xml b/tobago-theme/pom.xml
index b00725b..005913e 100644
--- a/tobago-theme/pom.xml
+++ b/tobago-theme/pom.xml
@@ -88,6 +88,8 @@
                     <include>fonts/**</include>
                     <include>js/tobago.js</include>
                     <include>js/tobago.js.map</include>
+                    <include>js/tobago*.js</include>
+                    <include>js/tobago*.js.map</include>
                   </includes>
                 </resource>
                 <resource>
diff --git a/tobago-theme/tobago-theme-standard/npm/.eslintignore b/tobago-theme/tobago-theme-standard/npm/.eslintignore
new file mode 100644
index 0000000..cc8701c
--- /dev/null
+++ b/tobago-theme/tobago-theme-standard/npm/.eslintignore
@@ -0,0 +1,4 @@
+dist/
+lib/
+node_modules/
+*.js
diff --git a/tobago-theme/tobago-theme-standard/npm/.eslintrc.js b/tobago-theme/tobago-theme-standard/npm/.eslintrc.js
new file mode 100644
index 0000000..c7c4b81
--- /dev/null
+++ b/tobago-theme/tobago-theme-standard/npm/.eslintrc.js
@@ -0,0 +1,68 @@
+module.exports = {
+  parser: '@typescript-eslint/parser',
+  plugins: ['@typescript-eslint'],
+  extends: [
+    'plugin:@typescript-eslint/recommended',
+    'plugin:@typescript-eslint/eslint-recommended',
+    'plugin:@typescript-eslint/recommended'
+  ],
+  parserOptions: {
+    project: './tsconfig.json',
+    ecmaVersion: 2018,
+    sourceType: 'module',
+  },
+  rules: {
+    "prefer-const": "warn",
+    "prefer-rest-params": "warn",
+    "no-case-declarations": "warn",
+    "no-irregular-whitespace": "warn",
+    "no-constant-condition": "warn",
+    "no-inner-declarations": "warn",
+    "@typescript-eslint/ban-ts-comment": "warn",
+    "@typescript-eslint/no-implied-eval": "warn",
+    "@typescript-eslint/unbound-method": "warn",
+    "@typescript-eslint/no-unsafe-call": "warn",
+    "@typescript-eslint/no-unsafe-assignment": "warn",
+    "@typescript-eslint/no-unsafe-member-access": "warn",
+    "@typescript-eslint/restrict-template-expressions": "warn",
+    "@typescript-eslint/indent": [
+      "warn",
+      2
+    ],
+    "@typescript-eslint/member-delimiter-style": [
+      "warn",
+      {
+        "multiline": {
+          "delimiter": "semi",
+          "requireLast": true
+        },
+        "singleline": {
+          "delimiter": "semi",
+          "requireLast": false
+        }
+      }
+    ],
+    "@typescript-eslint/member-ordering": "warn",
+    "@typescript-eslint/no-unnecessary-type-assertion": ["warn"],
+    "@typescript-eslint/no-empty-function": "warn",
+    "@typescript-eslint/no-inferrable-types": "warn",
+    "@typescript-eslint/restrict-plus-operands": "warn",
+    "@typescript-eslint/no-unsafe-return": "warn",
+    "@typescript-eslint/quotes": [
+      "warn",
+      "double"
+    ],
+    "@typescript-eslint/semi": [
+      "error",
+      "always"
+    ],
+    "max-len": [
+      "warn",
+      {
+        "code": 120
+      }
+    ],
+    "no-multiple-empty-lines": "error",
+    "no-var": "warn"
+  }
+}
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/css/font-awesome.min.css b/tobago-theme/tobago-theme-standard/npm/dist/css/font-awesome.min.css
new file mode 100644
index 0000000..540440c
--- /dev/null
+++ b/tobago-theme/tobago-theme-standard/npm/dist/css/font-awesome.min.css
@@ -0,0 +1,4 @@
+/*!
+ *  Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome
+ *  License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
+ */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.7.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.7.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.7.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.7.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular') format('svg');font-weight:normal;font-style:norma [...]
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-all.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-all.js.map
index f54aea0..5505255 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-all.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-all.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-all.js","sourceRoot":"","sources":["../../ts/tobago-all.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,mBAAmB,CAAC;AAC3B,OAAO,cAAc,CAAC;AACtB,OAAO,mBAAmB,CAAC;AAC3B,OAAO,eAAe,CAAC;AACvB,OAAO,kBAAkB,CAAC;AAC1B,OAAO,eAAe,CAAC;AACvB,OAAO,gBAAgB,CAAC;AACxB,OAAO,iBAAiB,CAAC;AACzB,OAAO,aAAa,CAAC;AACrB,OAAO,mBAAmB,CAAC;AAC3B,OAAO,kBAAkB,CAAC;AAC1B,OAAO,gBAAgB,CAAC;AACxB,OAAO,mBAAmB,CAAC;AAC3B,OAAO,kBAAkB,CAAC;AAC1B,OAAO,gBAAgB,CAAC;AACxB,OAAO,gBAAgB,CA [...]
\ No newline at end of file
+{"version":3,"file":"tobago-all.js","sourceRoot":"../ts/","sources":["tobago-all.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,mBAAmB,CAAC;AAC3B,OAAO,cAAc,CAAC;AACtB,OAAO,mBAAmB,CAAC;AAC3B,OAAO,eAAe,CAAC;AACvB,OAAO,kBAAkB,CAAC;AAC1B,OAAO,eAAe,CAAC;AACvB,OAAO,gBAAgB,CAAC;AACxB,OAAO,iBAAiB,CAAC;AACzB,OAAO,aAAa,CAAC;AACrB,OAAO,mBAAmB,CAAC;AAC3B,OAAO,kBAAkB,CAAC;AAC1B,OAAO,gBAAgB,CAAC;AACxB,OAAO,mBAAmB,CAAC;AAC3B,OAAO,kBAAkB,CAAC;AAC1B,OAAO,gBAAgB,CAAC;AACxB,OAAO,gBAAgB,CAAC; [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-bar.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-bar.js.map
index f79831c..4356cef 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-bar.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-bar.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-bar.js","sourceRoot":"","sources":["../../ts/tobago-bar.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,QAAQ,EAAC,MAAM,gBAAgB,CAAC;AAExC,MAAM,GAAI,SAAQ,WAAW;IAW3B;QACE,KAAK,EAAE,CAAC;QAVO,aAAQ,GAAG;YAC1B,IAAI,EAAE,MAAM;YACZ,QAAQ,EAAE,UAAU;YACpB,UAAU,EAAE,YAAY;SACzB,CAAC;QACe,iBAAY,GAAW,eAAe,CAAC;QAMtD,IAAI,CAAC,YAAY,CAAC,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9E,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,QAAQ,GAAG,IA [...]
\ No newline at end of file
+{"version":3,"file":"tobago-bar.js","sourceRoot":"../ts/","sources":["tobago-bar.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,QAAQ,EAAC,MAAM,gBAAgB,CAAC;AAExC,MAAM,GAAI,SAAQ,WAAW;IAW3B;QACE,KAAK,EAAE,CAAC;QAVO,aAAQ,GAAG;YAC1B,IAAI,EAAE,MAAM;YACZ,QAAQ,EAAE,UAAU;YACpB,UAAU,EAAE,YAAY;SACzB,CAAC;QACe,iBAAY,GAAW,eAAe,CAAC;QAMtD,IAAI,CAAC,YAAY,CAAC,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9E,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,QAAQ,GAAG,IAAI, [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-command.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-command.js.map
index 8bd5e4e..5334f73 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-command.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-command.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-command.js","sourceRoot":"","sources":["../../ts/tobago-command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,QAAQ,EAAC,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAC,OAAO,EAAC,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAC,QAAQ,EAAC,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAAC,IAAI,EAAC,MAAM,eAAe,CAAC;AAEnC,MAAM,QAAS,SAAQ,WAAW;IAEhC;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QACf,QAAQ,IAAI,CAAC,KAAK,EAAE;YAClB,KAAK,MAAM,EAAE,8DAA8D;gBACzE,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAChB,MAAM;YAC [...]
\ No newline at end of file
+{"version":3,"file":"tobago-command.js","sourceRoot":"../ts/","sources":["tobago-command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,QAAQ,EAAC,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAC,OAAO,EAAC,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAC,QAAQ,EAAC,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAAC,IAAI,EAAC,MAAM,eAAe,CAAC;AAEnC,MAAM,QAAS,SAAQ,WAAW;IAEhC;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QACf,QAAQ,IAAI,CAAC,KAAK,EAAE;YAClB,KAAK,MAAM,EAAE,8DAA8D;gBACzE,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAChB,MAAM;YACR,K [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-config.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-config.js.map
index ae5ca21..5c37161 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-config.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-config.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-config.js","sourceRoot":"","sources":["../../ts/tobago-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,OAAO,MAAM;IAIjB,MAAM,CAAC,GAAG,CAAC,GAAW,EAAE,KAAU;QAChC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC3B,CAAC;IAED,MAAM,CAAC,GAAG,CAAC,GAAW;QACpB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAChC,IAAI,KAAK,EAAE;YACT,OAAO,KAAK,CAAC;SACd;aAAM;YACL,OAAO,CAAC,IAAI,CAAC,aAAa,GAAG,GAAG,GAAG,eAAe,CAAC,CAAC;YACpD,OAAO [...]
\ No newline at end of file
+{"version":3,"file":"tobago-config.js","sourceRoot":"../ts/","sources":["tobago-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,OAAO,MAAM;IAIjB,MAAM,CAAC,GAAG,CAAC,GAAW,EAAE,KAAU;QAChC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC3B,CAAC;IAED,MAAM,CAAC,GAAG,CAAC,GAAW;QACpB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAChC,IAAI,KAAK,EAAE;YACT,OAAO,KAAK,CAAC;SACd;aAAM;YACL,OAAO,CAAC,IAAI,CAAC,aAAa,GAAG,GAAG,GAAG,eAAe,CAAC,CAAC;YACpD,OAAO,CA [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-date.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-date.js.map
index 2baff47..4657028 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-date.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-date.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-date.js","sourceRoot":"","sources":["../../ts/tobago-date.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,aAAa;AACb,OAAO,EAAC,UAAU,EAAC,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAC,IAAI,EAAC,MAAM,eAAe,CAAC;AAyBnC,MAAM,UAAW,SAAQ,WAAW;IAIlC;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;;QACf,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACzB,MAAM,MAAM,GAAW,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;QAE9C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACvB,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,CA [...]
\ No newline at end of file
+{"version":3,"file":"tobago-date.js","sourceRoot":"../ts/","sources":["tobago-date.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,aAAa;AACb,OAAO,EAAC,UAAU,EAAC,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAC,IAAI,EAAC,MAAM,eAAe,CAAC;AAyBnC,MAAM,UAAW,SAAQ,WAAW;IAIlC;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;;QACf,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACzB,MAAM,MAAM,GAAW,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;QAE9C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;QACvB,IAAI,CAAC,WAAW,GAAG,MAAM,CAAC,CAAC, [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-dropdown.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-dropdown.js.map
index 2adc211..5c85b84 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-dropdown.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-dropdown.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-dropdown.js","sourceRoot":"","sources":["../../ts/tobago-dropdown.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,mBAAmB,GAAG;IAC1B,IAAI,EAAE,sBAAsB;IAC5B,MAAM,EAAE,wBAAwB;IAChC,IAAI,EAAE,sBAAsB;IAC5B,KAAK,EAAE,uBAAuB;CAC/B,CAAC;AAEF;;;GAGG;AACH,MAAM,QAAS,SAAQ,WAAW;IAEhC;QACE,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,yBAAyB,CAAC,EAAE,EAAE,kBAAkB;YAC3E,IAAI,CAAC,gBAAgB,CAAC,mBAAmB,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC [...]
\ No newline at end of file
+{"version":3,"file":"tobago-dropdown.js","sourceRoot":"../ts/","sources":["tobago-dropdown.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,mBAAmB,GAAG;IAC1B,IAAI,EAAE,sBAAsB;IAC5B,MAAM,EAAE,wBAAwB;IAChC,IAAI,EAAE,sBAAsB;IAC5B,KAAK,EAAE,uBAAuB;CAC/B,CAAC;AAEF;;;GAGG;AACH,MAAM,QAAS,SAAQ,WAAW;IAEhC;QACE,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,yBAAyB,CAAC,EAAE,EAAE,kBAAkB;YAC3E,IAAI,CAAC,gBAAgB,CAAC,mBAAmB,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CA [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-example.js b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-example.js
deleted file mode 100644
index dcb308b..0000000
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-example.js
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-// XXX it might be nice, if this util was in tobago-date.ts, but in that case there are problems
-// XXX with Jest (UnitTesting)
-export class Example {
-    /*
-    example file to demonstrate TypeScript tests.
-    */
-    static toUpperCase(text) {
-        return text === null || text === void 0 ? void 0 : text.toUpperCase();
-    }
-}
-//# sourceMappingURL=tobago-example.js.map
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-example.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-example.js.map
deleted file mode 100644
index 1daa6c0..0000000
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-example.js.map
+++ /dev/null
@@ -1 +0,0 @@
-{"version":3,"file":"tobago-example.js","sourceRoot":"","sources":["../../ts/tobago-example.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,gGAAgG;AAChG,8BAA8B;AAE9B,MAAM,OAAO,OAAO;IAElB;;MAEE;IACK,MAAM,CAAC,WAAW,CAAC,IAAY;QACpC,OAAO,IAAI,aAAJ,IAAI,uBAAJ,IAAI,CAAE,WAAW,GAAG;IAC7B,CAAC;CACF"}
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-file.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-file.js.map
index f21e843..ddd29f3 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-file.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-file.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-file.js","sourceRoot":"","sources":["../../ts/tobago-file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,OAAO,IAAK,SAAQ,WAAW;IAEnC;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,GAAG,qBAAqB,CAAC;IAClD,CAAC;IAED,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;CACF;AAED,QAAQ,CAAC,gBAAgB,CAAC,aAAa,EAAE,UAAU,KAAY;IAC7D,IAAI,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,IAAI,EAAE;QACpD,MAAM,CAAC,cAA [...]
\ No newline at end of file
+{"version":3,"file":"tobago-file.js","sourceRoot":"../ts/","sources":["tobago-file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,OAAO,IAAK,SAAQ,WAAW;IAEnC;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,GAAG,qBAAqB,CAAC;IAClD,CAAC;IAED,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;CACF;AAED,QAAQ,CAAC,gBAAgB,CAAC,aAAa,EAAE,UAAU,KAAY;IAC7D,IAAI,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,IAAI,EAAE;QACpD,MAAM,CAAC,cAAc,C [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-focus.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-focus.js.map
index 8e67bbf..cec15b1 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-focus.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-focus.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-focus.js","sourceRoot":"","sources":["../../ts/tobago-focus.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,IAAI,EAAC,MAAM,eAAe,CAAC;AAGnC,MAAM,OAAO,KAAM,SAAQ,WAAW;IAEpC;;;OAGG;IACH,MAAM,CAAC,cAAc,CAAC,KAAiB;QACrC,MAAM,MAAM,GAAG,KAAK,CAAC,MAAqB,CAAC;QAC3C,IAAI,aAAa,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;QAE7C,IAAI,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,QAAQ;eACrC,MAAM,CAAC,iBAAiB,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;eACrD,MAAM,CAAC,YAAY,CAAC,UA [...]
\ No newline at end of file
+{"version":3,"file":"tobago-focus.js","sourceRoot":"../ts/","sources":["tobago-focus.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,IAAI,EAAC,MAAM,eAAe,CAAC;AAGnC,MAAM,OAAO,KAAM,SAAQ,WAAW;IAEpC;;;OAGG;IACH,MAAM,CAAC,cAAc,CAAC,KAAiB;QACrC,MAAM,MAAM,GAAG,KAAK,CAAC,MAAqB,CAAC;QAC3C,IAAI,aAAa,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;QAE7C,IAAI,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,KAAK,QAAQ;eACrC,MAAM,CAAC,iBAAiB,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;eACrD,MAAM,CAAC,YAAY,CAAC,UAAU, [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-footer.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-footer.js.map
index a2ef460..eefed51 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-footer.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-footer.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-footer.js","sourceRoot":"","sources":["../../ts/tobago-footer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,MAAO,SAAQ,WAAW;IAI9B;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QACf,IAAI,IAAI,CAAC,OAAO,EAAE;YAChB,WAAW;YACX,IAAI,CAAC,YAAY,EAAE,CAAC;YACpB,mBAAmB;YACnB,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;SACjE;IACH,CAAC;IAEO,YAAY,CAAC,KAAkB;QACrC,MAAM,KAAK,GAAwB,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACjE,MAA [...]
\ No newline at end of file
+{"version":3,"file":"tobago-footer.js","sourceRoot":"../ts/","sources":["tobago-footer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,MAAO,SAAQ,WAAW;IAI9B;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QACf,IAAI,IAAI,CAAC,OAAO,EAAE;YAChB,WAAW;YACX,IAAI,CAAC,YAAY,EAAE,CAAC;YACpB,mBAAmB;YACnB,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;SACjE;IACH,CAAC;IAEO,YAAY,CAAC,KAAkB;QACrC,MAAM,KAAK,GAAwB,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACjE,MAAM,e [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-in.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-in.js.map
index 4a2ee16..ca422f7 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-in.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-in.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-in.js","sourceRoot":"","sources":["../../ts/tobago-in.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,QAAQ,EAAE,KAAK,EAAC,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAC,KAAK,EAAC,MAAM,gBAAgB,CAAC;AACrC,OAAO,EAAC,OAAO,EAAC,MAAM,kBAAkB,CAAC;AAEzC,MAAM,OAAO,EAAG,SAAQ,WAAW;IACjC;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;QAC3D,IAAI,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,EAAE;YACxC,MAAM,OAAO,GAAG, [...]
\ No newline at end of file
+{"version":3,"file":"tobago-in.js","sourceRoot":"../ts/","sources":["tobago-in.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,QAAQ,EAAE,KAAK,EAAC,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAC,KAAK,EAAC,MAAM,gBAAgB,CAAC;AACrC,OAAO,EAAC,OAAO,EAAC,MAAM,kBAAkB,CAAC;AAEzC,MAAM,OAAO,EAAG,SAAQ,WAAW;IACjC;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;QAC3D,IAAI,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,EAAE;YACxC,MAAM,OAAO,GAAG,IAA [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-listener.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-listener.js.map
index eb5ddbe..f1d34ae 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-listener.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-listener.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-listener.js","sourceRoot":"","sources":["../../ts/tobago-listener.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,CAAN,IAAY,KAaX;AAbD,WAAY,KAAK;IACf,8BAA8B;IAC9B,qDAAc,CAAA;IACd,0CAA0C;IAC1C,+CAAW,CAAA;IACX,4CAA4C;IAC5C,mDAAa,CAAA;IACb,yBAAyB;IACzB,iDAAY,CAAA;IACZ,2BAA2B;IAC3B,mDAAa,CAAA;IACb,qCAAqC;IACrC,+CAAW,CAAA;AACb,CAAC,EAbW,KAAK,KAAL,KAAK,QAahB;AAED,MAAM,CAAN,IAAY,KAMX;AAND,WAAY,KAAK;IACf,uCAAW,CAAA;IACX,mCAAS,CAAA;IACT,qCAAU,CAAA;IACV,iCA [...]
\ No newline at end of file
+{"version":3,"file":"tobago-listener.js","sourceRoot":"../ts/","sources":["tobago-listener.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,CAAN,IAAY,KAaX;AAbD,WAAY,KAAK;IACf,8BAA8B;IAC9B,qDAAc,CAAA;IACd,0CAA0C;IAC1C,+CAAW,CAAA;IACX,4CAA4C;IAC5C,mDAAa,CAAA;IACb,yBAAyB;IACzB,iDAAY,CAAA;IACZ,2BAA2B;IAC3B,mDAAa,CAAA;IACb,qCAAqC;IACrC,+CAAW,CAAA;AACb,CAAC,EAbW,KAAK,KAAL,KAAK,QAahB;AAED,MAAM,CAAN,IAAY,KAMX;AAND,WAAY,KAAK;IACf,uCAAW,CAAA;IACX,mCAAS,CAAA;IACT,qCAAU,CAAA;IACV,iCAAQ, [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-messages.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-messages.js.map
index 0bf4c62..d94970a 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-messages.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-messages.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-messages.js","sourceRoot":"","sources":["../../ts/tobago-messages.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,QAAS,SAAQ,WAAW;IAEhC;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QACf,KAAK,IAAI,WAAW,IAAI,IAAI,CAAC,YAAY,EAAE;YACzC,WAAW,CAAC,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;SACxD;IACH,CAAC;IAEO,UAAU,CAAC,KAAiB;QAClC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,CAAC;IAClC,CAAC;IAED,IAAI,YAAY;QACd,OAAO,IAAI,CAAC,gBAAgB,CAAC,yBAAyB,CAAC,CA [...]
\ No newline at end of file
+{"version":3,"file":"tobago-messages.js","sourceRoot":"../ts/","sources":["tobago-messages.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,QAAS,SAAQ,WAAW;IAEhC;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QACf,KAAK,IAAI,WAAW,IAAI,IAAI,CAAC,YAAY,EAAE;YACzC,WAAW,CAAC,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;SACxD;IACH,CAAC;IAEO,UAAU,CAAC,KAAiB;QAClC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,CAAC;IAClC,CAAC;IAED,IAAI,YAAY;QACd,OAAO,IAAI,CAAC,gBAAgB,CAAC,yBAAyB,CAAC,CAAC; [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-overlay.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-overlay.js.map
index c35198d..e72b30f 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-overlay.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-overlay.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-overlay.js","sourceRoot":"","sources":["../../ts/tobago-overlay.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH;;GAEG;AAEH,OAAO,EAAC,MAAM,EAAC,MAAM,iBAAiB,CAAC;AACvC,OAAO,EAAC,IAAI,EAAC,MAAM,eAAe,CAAC;AAEnC,qHAAqH;AACrH,kDAAkD;AAClD,iHAAiH;AACjH,wCAAwC;AAExC,MAAM,OAAO,OAAO;IAoClB,YAAY,OAAoB,EAAE,IAAI,GAAG,KAAK,EAAE,KAAK,GAAG,KAAK,EAAE,gBAAiB;QAhChF;;;;WAIG;QACH,SAAI,GAAY,IAAI,CAAC;QAErB;;WAEG;QACH,UAAK,GAAY,KAAK,CAAC;QAEvB;;WAEG;QACH,qBAAgB,GAAW,CAAC, [...]
\ No newline at end of file
+{"version":3,"file":"tobago-overlay.js","sourceRoot":"../ts/","sources":["tobago-overlay.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH;;GAEG;AAEH,OAAO,EAAC,MAAM,EAAC,MAAM,iBAAiB,CAAC;AACvC,OAAO,EAAC,IAAI,EAAC,MAAM,eAAe,CAAC;AAEnC,qHAAqH;AACrH,kDAAkD;AAClD,iHAAiH;AACjH,wCAAwC;AAExC,MAAM,OAAO,OAAO;IAoClB,YAAY,OAAoB,EAAE,IAAI,GAAG,KAAK,EAAE,KAAK,GAAG,KAAK,EAAE,gBAAiB;QAhChF;;;;WAIG;QACH,SAAI,GAAY,IAAI,CAAC;QAErB;;WAEG;QACH,UAAK,GAAY,KAAK,CAAC;QAEvB;;WAEG;QACH,qBAAgB,GAAW,CAAC,CAA [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-page.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-page.js.map
index d07a87d..b9f2a01 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-page.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-page.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-page.js","sourceRoot":"","sources":["../../ts/tobago-page.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,aAAa,EAAC,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAC,OAAO,EAAC,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAC,QAAQ,EAAC,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAE9C,MAAM,OAAO,IAAK,SAAQ,WAAW;IAoDnC;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAjDD;;OAEG;IACH,MAAM,CAAC,IAAI,CAAC,OAAoB;QAC9B,MAAM,QAAQ,GAAG,OAAO,CAAC,WAAW,EAA2B,CAAC;QAChE,MAAM,KAAK,GAAG,QAAQ [...]
\ No newline at end of file
+{"version":3,"file":"tobago-page.js","sourceRoot":"../ts/","sources":["tobago-page.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,aAAa,EAAC,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAC,OAAO,EAAC,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAC,QAAQ,EAAC,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAE9C,MAAM,OAAO,IAAK,SAAQ,WAAW;IAoDnC;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAjDD;;OAEG;IACH,MAAM,CAAC,IAAI,CAAC,OAAoB;QAC9B,MAAM,QAAQ,GAAG,OAAO,CAAC,WAAW,EAA2B,CAAC;QAChE,MAAM,KAAK,GAAG,QAAQ,CA [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-panel.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-panel.js.map
index 62b0e77..bf5910f 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-panel.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-panel.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-panel.js","sourceRoot":"","sources":["../../ts/tobago-panel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,KAAM,SAAQ,WAAW;CAC9B;AAED,QAAQ,CAAC,gBAAgB,CAAC,aAAa,EAAE,UAAU,KAAY;IAC7D,IAAI,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,IAAI,EAAE;QACrD,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;KACrD;AACH,CAAC,CAAC,CAAC"}
\ No newline at end of file
+{"version":3,"file":"tobago-panel.js","sourceRoot":"../ts/","sources":["tobago-panel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,KAAM,SAAQ,WAAW;CAC9B;AAED,QAAQ,CAAC,gBAAgB,CAAC,aAAa,EAAE,UAAU,KAAY;IAC7D,IAAI,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,IAAI,EAAE;QACrD,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;KACrD;AACH,CAAC,CAAC,CAAC","sourcesContent":["/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor license agreem [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-polyfill.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-polyfill.js.map
index 4e07e08..474d94e 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-polyfill.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-polyfill.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-polyfill.js","sourceRoot":"","sources":["../../ts/tobago-polyfill.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,qHAAqH;AAErH,iCAAiC;AACjC,IAAI;IACF,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;CAClC;AAAC,OAAO,SAAS,EAAE;IAClB,MAAM,sBAAsB,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;IACzE,OAAO,CAAC,SAAS,CAAC,aAAa,GAAG,SAAS,aAAa,CAAC,SAAiB;QACxE,OAAO,sBAAsB,CAAC,KAAK,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IACvD,CAAC,CAAC;IAEF,MAAM,yBAAyB,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS [...]
\ No newline at end of file
+{"version":3,"file":"tobago-polyfill.js","sourceRoot":"../ts/","sources":["tobago-polyfill.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,qHAAqH;AAErH,iCAAiC;AACjC,IAAI;IACF,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;CAClC;AAAC,OAAO,SAAS,EAAE;IAClB,MAAM,sBAAsB,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;IACzE,OAAO,CAAC,SAAS,CAAC,aAAa,GAAG,SAAS,aAAa,CAAC,SAAiB;QACxE,OAAO,sBAAsB,CAAC,KAAK,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IACvD,CAAC,CAAC;IAEF,MAAM,yBAAyB,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS,CA [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-popover.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-popover.js.map
index bb72ee3..c628bcd 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-popover.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-popover.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-popover.js","sourceRoot":"","sources":["../../ts/tobago-popover.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,8BAA8B;AAC9B,4DAA4D;AAC5D,4DAA4D;AAC5D,+DAA+D;AAC/D,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAC;AAClC,8DAA8D;AAE9D,MAAM,aAAc,SAAQ,WAAW;IAIrC;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,OAAO,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE;YACvC,SAAS,EAAE,IAAI,CAAC,SAAS;SAC1B,CAAC,CAAC;IACL,CAAC;IAED,IAAI,OAAO;QACT,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IA [...]
\ No newline at end of file
+{"version":3,"file":"tobago-popover.js","sourceRoot":"../ts/","sources":["tobago-popover.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,8BAA8B;AAC9B,4DAA4D;AAC5D,4DAA4D;AAC5D,+DAA+D;AAC/D,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAC;AAClC,8DAA8D;AAE9D,MAAM,aAAc,SAAQ,WAAW;IAIrC;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,OAAO,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE;YACvC,SAAS,EAAE,IAAI,CAAC,SAAS;SAC1B,CAAC,CAAC;IACL,CAAC;IAED,IAAI,OAAO;QACT,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAY, [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-popup.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-popup.js.map
index c59394f..7e17cf6 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-popup.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-popup.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-popup.js","sourceRoot":"","sources":["../../ts/tobago-popup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,gEAAgE;AAChE,4CAA4C;AAC5C,wCAAwC;AACxC,OAAO,EAAC,KAAK,EAAC,MAAM,WAAW,CAAC;AAChC,4DAA4D;AAE5D,MAAM,OAAO,KAAM,SAAQ,WAAW;IAIpC;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QAChB,IAAI,OAAO,GAAG,EAAE,CAAC;QAEhB,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACxC,CAAC;IAED,IAAI;QACF,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpB,IAAI,CAAC,KAAK,CA [...]
\ No newline at end of file
+{"version":3,"file":"tobago-popup.js","sourceRoot":"../ts/","sources":["tobago-popup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,gEAAgE;AAChE,4CAA4C;AAC5C,wCAAwC;AACxC,OAAO,EAAC,KAAK,EAAC,MAAM,WAAW,CAAC;AAChC,4DAA4D;AAE5D,MAAM,OAAO,KAAM,SAAQ,WAAW;IAIpC;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QAChB,IAAI,OAAO,GAAG,EAAE,CAAC;QAEhB,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACxC,CAAC;IAED,IAAI;QACF,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpB,IAAI,CAAC,KAAK,CAAC, [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-range.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-range.js.map
index 3ec329c..9467692 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-range.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-range.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-range.js","sourceRoot":"","sources":["../../ts/tobago-range.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAC;AAElC,MAAM,WAAY,SAAQ,WAAW;IAInC;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,OAAO,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE;YACrC,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;YAChC,OAAO,EAAE,OAAO;YAChB,SAAS,EAAE,MAAM;YACjB,KAAK,EAAE;gBACL,IAAI,EAAE,CAAC;gBACP,IAAI,E [...]
\ No newline at end of file
+{"version":3,"file":"tobago-range.js","sourceRoot":"../ts/","sources":["tobago-range.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAC;AAElC,MAAM,WAAY,SAAQ,WAAW;IAInC;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,OAAO,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,EAAE;YACrC,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;YAChC,OAAO,EAAE,OAAO;YAChB,SAAS,EAAE,MAAM;YACjB,KAAK,EAAE;gBACL,IAAI,EAAE,CAAC;gBACP,IAAI,EAAE [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-reload.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-reload.js.map
index aefd2d4..77e111e 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-reload.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-reload.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-reload.js","sourceRoot":"","sources":["../../ts/tobago-reload.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,QAAQ,EAAE,KAAK,EAAC,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAC,QAAQ,EAAC,MAAM,gBAAgB,CAAC;AAExC,kDAAkD;AAClD,MAAM,OAAO,aAAa;IAexB;QACE,IAAI,CAAC,QAAQ,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC5C,CAAC;IAEM,QAAQ,CAAC,EAAU,EAAE,YAAoB;QAC9C,IAAI,YAAY,GAAG,CAAC,EAAE;YAEpB,0BAA0B;YAC1B,IAAI,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACvC,IAAI,UAAU,E [...]
\ No newline at end of file
+{"version":3,"file":"tobago-reload.js","sourceRoot":"../ts/","sources":["tobago-reload.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,QAAQ,EAAE,KAAK,EAAC,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAC,QAAQ,EAAC,MAAM,gBAAgB,CAAC;AAExC,kDAAkD;AAClD,MAAM,OAAO,aAAa;IAexB;QACE,IAAI,CAAC,QAAQ,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC5C,CAAC;IAEM,QAAQ,CAAC,EAAU,EAAE,YAAoB;QAC9C,IAAI,YAAY,GAAG,CAAC,EAAE;YAEpB,0BAA0B;YAC1B,IAAI,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACvC,IAAI,UAAU,EAAE [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-scroll.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-scroll.js.map
index f624cb9..36fd090 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-scroll.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-scroll.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-scroll.js","sourceRoot":"","sources":["../../ts/tobago-scroll.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAC,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAC,QAAQ,EAAC,MAAM,gBAAgB,CAAC;AAExC,MAAM,MAAM;;AAEH,yBAAkB,GAAG,UAAU,OAAoB;IACxD,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,sBAAsB,CAAC,OAAO,EAAE,4BAA4B,CAAC,EAAE;QAE1F,MAAM,MAAM,GAAG,KAAK,CAAC,aAAa,CAAC,wCAAwC,CAAqB,CAAC;QACjG,MAAM,MAAM,GAAa,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC; [...]
\ No newline at end of file
+{"version":3,"file":"tobago-scroll.js","sourceRoot":"../ts/","sources":["tobago-scroll.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAC,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAC,QAAQ,EAAC,MAAM,gBAAgB,CAAC;AAExC,MAAM,MAAM;;AAEH,yBAAkB,GAAG,UAAU,OAAoB;IACxD,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,sBAAsB,CAAC,OAAO,EAAE,4BAA4B,CAAC,EAAE;QAE1F,MAAM,MAAM,GAAG,KAAK,CAAC,aAAa,CAAC,wCAAwC,CAAqB,CAAC;QACjG,MAAM,MAAM,GAAa,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-select-boolean-checkbox.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-select-boolean-checkbox.js.map
index a4d0495..ff756d3 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-select-boolean-checkbox.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-select-boolean-checkbox.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-select-boolean-checkbox.js","sourceRoot":"","sources":["../../ts/tobago-select-boolean-checkbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAC,KAAK,EAAC,MAAM,gBAAgB,CAAC;AAErC,MAAM,OAAO,qBAAsB,SAAQ,WAAW;IAEpD;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;QAE3D,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE;YACvB,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;SACpD;QAED,SAAS,Y [...]
\ No newline at end of file
+{"version":3,"file":"tobago-select-boolean-checkbox.js","sourceRoot":"../ts/","sources":["tobago-select-boolean-checkbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAC,KAAK,EAAC,MAAM,gBAAgB,CAAC;AAErC,MAAM,OAAO,qBAAsB,SAAQ,WAAW;IAEpD;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;QAE3D,IAAI,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE;YACvB,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;SACpD;QAED,SAAS,YAAY [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-select-boolean-toggle.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-select-boolean-toggle.js.map
index 65b8f17..a6538f7 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-select-boolean-toggle.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-select-boolean-toggle.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-select-boolean-toggle.js","sourceRoot":"","sources":["../../ts/tobago-select-boolean-toggle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,qBAAqB,EAAC,MAAM,kCAAkC,CAAC;AAEvE,MAAM,mBAAoB,SAAQ,qBAAqB;CACtD;AAED,QAAQ,CAAC,gBAAgB,CAAC,aAAa,EAAE,UAAU,KAAY;IAC7D,IAAI,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,8BAA8B,CAAC,IAAI,IAAI,EAAE;QACrE,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,8BAA8B,EAAE,mBAAmB,CAAC,CAAC;KACnF;AACH,CAAC,CAAC,CAAC"}
\ No newline at end of file
+{"version":3,"file":"tobago-select-boolean-toggle.js","sourceRoot":"../ts/","sources":["tobago-select-boolean-toggle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,qBAAqB,EAAC,MAAM,kCAAkC,CAAC;AAEvE,MAAM,mBAAoB,SAAQ,qBAAqB;CACtD;AAED,QAAQ,CAAC,gBAAgB,CAAC,aAAa,EAAE,UAAU,KAAY;IAC7D,IAAI,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,8BAA8B,CAAC,IAAI,IAAI,EAAE;QACrE,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,8BAA8B,EAAE,mBAAmB,CAAC,CAAC;KACnF;AACH,CAAC,CAAC,CAAC","sourcesContent":["/*\n * Licensed t [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-select-many-checkbox.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-select-many-checkbox.js.map
index a7b7c4d..a556550 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-select-many-checkbox.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-select-many-checkbox.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-select-many-checkbox.js","sourceRoot":"","sources":["../../ts/tobago-select-many-checkbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,KAAK,EAAC,MAAM,gBAAgB,CAAC;AAErC,MAAM,kBAAmB,SAAQ,WAAW;IAE1C;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QACf,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE;YAC/B,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;YAEtD,IAAI,KAAK,CAAC,QAAQ,EAAE;gBAClB,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;aAC/C;YAED, [...]
\ No newline at end of file
+{"version":3,"file":"tobago-select-many-checkbox.js","sourceRoot":"../ts/","sources":["tobago-select-many-checkbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,KAAK,EAAC,MAAM,gBAAgB,CAAC;AAErC,MAAM,kBAAmB,SAAQ,WAAW;IAE1C;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QACf,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE;YAC/B,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;YAEtD,IAAI,KAAK,CAAC,QAAQ,EAAE;gBAClB,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;aAC/C;YAED,SAA [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-select-many-listbox.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-select-many-listbox.js.map
index 367436d..6ab1b52 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-select-many-listbox.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-select-many-listbox.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-select-many-listbox.js","sourceRoot":"","sources":["../../ts/tobago-select-many-listbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,gBAAgB,EAAC,MAAM,6BAA6B,CAAC;AAE7D,MAAM,iBAAkB,SAAQ,gBAAgB;CAC/C;AAED,QAAQ,CAAC,gBAAgB,CAAC,aAAa,EAAE,UAAU,KAAY;IAC7D,IAAI,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,4BAA4B,CAAC,IAAI,IAAI,EAAE;QACnE,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,4BAA4B,EAAE,iBAAiB,CAAC,CAAC;KAC/E;AACH,CAAC,CAAC,CAAC"}
\ No newline at end of file
+{"version":3,"file":"tobago-select-many-listbox.js","sourceRoot":"../ts/","sources":["tobago-select-many-listbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,gBAAgB,EAAC,MAAM,6BAA6B,CAAC;AAE7D,MAAM,iBAAkB,SAAQ,gBAAgB;CAC/C;AAED,QAAQ,CAAC,gBAAgB,CAAC,aAAa,EAAE,UAAU,KAAY;IAC7D,IAAI,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,4BAA4B,CAAC,IAAI,IAAI,EAAE;QACnE,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,4BAA4B,EAAE,iBAAiB,CAAC,CAAC;KAC/E;AACH,CAAC,CAAC,CAAC","sourcesContent":["/*\n * Licensed to th [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-select-many-shuttle.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-select-many-shuttle.js.map
index a968ad6..b2d464e 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-select-many-shuttle.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-select-many-shuttle.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-select-many-shuttle.js","sourceRoot":"","sources":["../../ts/tobago-select-many-shuttle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,KAAK,EAAC,MAAM,gBAAgB,CAAC;AAErC,MAAM,iBAAkB,SAAQ,WAAW;IAEzC;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,gBAAgB,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;QACtE,IAAI,CAAC,cAAc,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;QAEpE,IAAI,IAAI,CAAC,gBAAgB,CAAC,YAAY,CAAC,UAAU,CAAC,KAAK,U [...]
\ No newline at end of file
+{"version":3,"file":"tobago-select-many-shuttle.js","sourceRoot":"../ts/","sources":["tobago-select-many-shuttle.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,KAAK,EAAC,MAAM,gBAAgB,CAAC;AAErC,MAAM,iBAAkB,SAAQ,WAAW;IAEzC;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,gBAAgB,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;QACtE,IAAI,CAAC,cAAc,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;QAEpE,IAAI,IAAI,CAAC,gBAAgB,CAAC,YAAY,CAAC,UAAU,CAAC,KAAK,UAAU [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-select-one-choice.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-select-one-choice.js.map
index a187823..901c136 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-select-one-choice.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-select-one-choice.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-select-one-choice.js","sourceRoot":"","sources":["../../ts/tobago-select-one-choice.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAC,KAAK,EAAC,MAAM,gBAAgB,CAAC;AAErC,MAAM,eAAgB,SAAQ,WAAW;IACvC;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;IAC7D,CAAC;IAED,IAAI,KAAK;QACP,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAA2B,CAAC;QAC7D,OAAO,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,GAAG,SAAS,CAAqB,CAAC; [...]
\ No newline at end of file
+{"version":3,"file":"tobago-select-one-choice.js","sourceRoot":"../ts/","sources":["tobago-select-one-choice.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAC,KAAK,EAAC,MAAM,gBAAgB,CAAC;AAErC,MAAM,eAAgB,SAAQ,WAAW;IACvC;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;IAC7D,CAAC;IAED,IAAI,KAAK;QACP,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAA2B,CAAC;QAC7D,OAAO,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,GAAG,SAAS,CAAqB,CAAC;IAC [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-select-one-listbox.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-select-one-listbox.js.map
index 52ec3b5..88c034f 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-select-one-listbox.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-select-one-listbox.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-select-one-listbox.js","sourceRoot":"","sources":["../../ts/tobago-select-one-listbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,KAAK,EAAC,MAAM,gBAAgB,CAAC;AAErC,MAAM,OAAO,gBAAiB,SAAQ,WAAW;IAI/C;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,aAAa,EAAE,CAAC;QACrB,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACrE,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;IA [...]
\ No newline at end of file
+{"version":3,"file":"tobago-select-one-listbox.js","sourceRoot":"../ts/","sources":["tobago-select-one-listbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,KAAK,EAAC,MAAM,gBAAgB,CAAC;AAErC,MAAM,OAAO,gBAAiB,SAAQ,WAAW;IAI/C;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,aAAa,EAAE,CAAC;QACrB,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACrE,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;IAC7D [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-select-one-radio.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-select-one-radio.js.map
index 66d7736..8ef22bc 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-select-one-radio.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-select-one-radio.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-select-one-radio.js","sourceRoot":"","sources":["../../ts/tobago-select-one-radio.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,KAAK,EAAC,MAAM,gBAAgB,CAAC;AAErC,MAAM,cAAe,SAAQ,WAAW;IAItC;QACE,KAAK,EAAE,CAAC;QAHF,iBAAY,GAAW,EAAE,CAAC;IAIlC,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,aAAa,EAAE,CAAC;QACrB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,UAAU,EAAE;YACnC,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;YACtD,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC, [...]
\ No newline at end of file
+{"version":3,"file":"tobago-select-one-radio.js","sourceRoot":"../ts/","sources":["tobago-select-one-radio.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,KAAK,EAAC,MAAM,gBAAgB,CAAC;AAErC,MAAM,cAAe,SAAQ,WAAW;IAItC;QACE,KAAK,EAAE,CAAC;QAHF,iBAAY,GAAW,EAAE,CAAC;IAIlC,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,aAAa,EAAE,CAAC;QACrB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,UAAU,EAAE;YACnC,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;YACtD,KAAK,CAAC,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,cAA [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-selectable.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-selectable.js.map
index c9bc54c..4d8613f 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-selectable.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-selectable.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-selectable.js","sourceRoot":"","sources":["../../ts/tobago-selectable.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,CAAN,IAAY,UAUX;AAVD,WAAY,UAAU;IACpB,2CAAI,CAAA;IACJ,6CAAK,CAAA;IACL,+CAAM,CAAA;IACN,2DAAY,CAAA;IACZ,6DAAa,CAAA;IACb,+DAAc,CAAA;IACd,iDAAO,CAAA;IACP,iEAAe,CAAA;IACf,2DAAY,CAAA,CAAC,+FAA+F;AAC9G,CAAC,EAVW,UAAU,KAAV,UAAU,QAUrB"}
\ No newline at end of file
+{"version":3,"file":"tobago-selectable.js","sourceRoot":"../ts/","sources":["tobago-selectable.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,CAAN,IAAY,UAUX;AAVD,WAAY,UAAU;IACpB,2CAAI,CAAA;IACJ,6CAAK,CAAA;IACL,+CAAM,CAAA;IACN,2DAAY,CAAA;IACZ,6DAAa,CAAA;IACb,+DAAc,CAAA;IACd,iDAAO,CAAA;IACP,iEAAe,CAAA;IACf,2DAAY,CAAA,CAAC,+FAA+F;AAC9G,CAAC,EAVW,UAAU,KAAV,UAAU,QAUrB","sourcesContent":["/*\n * Licensed to the Apache Software Foundation (ASF) under one or more\n * contributor l [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-sheet.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-sheet.js.map
index 874ff38..c0e24d3 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-sheet.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-sheet.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-sheet.js","sourceRoot":"","sources":["../../ts/tobago-sheet.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAC,IAAI,EAAC,MAAM,eAAe,CAAC;AAEnC,MAAM,OAAO,KAAM,SAAQ,WAAW;IAsCpC;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IA/BO,MAAM,CAAC,gBAAgB;QAC7B,MAAM,IAAI,GAAG,QAAQ,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAE3D,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAC5C,KAAK,CAAC,KAAK,CAAC,UAAU,GAAG,QAAQ,CAAC;QAClC,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG, [...]
\ No newline at end of file
+{"version":3,"file":"tobago-sheet.js","sourceRoot":"../ts/","sources":["tobago-sheet.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAC,IAAI,EAAC,MAAM,eAAe,CAAC;AAEnC,MAAM,OAAO,KAAM,SAAQ,WAAW;IAsCpC;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IA/BO,MAAM,CAAC,gBAAgB;QAC7B,MAAM,IAAI,GAAG,QAAQ,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAE3D,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAC5C,KAAK,CAAC,KAAK,CAAC,UAAU,GAAG,QAAQ,CAAC;QAClC,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG,OAA [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-split-layout.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-split-layout.js.map
index 07a278f..7540777 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-split-layout.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-split-layout.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-split-layout.js","sourceRoot":"","sources":["../../ts/tobago-split-layout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,IAAI,EAAC,MAAM,eAAe,CAAC;AAEnC,MAAM,WAAY,SAAQ,WAAW;IAmBnC;QACE,KAAK,EAAE,CAAC;QAER,IAAI,KAAK,GAAG,IAAI,CAAC;QACjB,IAAI,SAAS,GAAG,KAAK,CAAC;QACtB,KAAK,IAAI,KAAK,IAAI,IAAI,CAAC,QAAQ,EAAE;YAC/B,IAAI,SAAS,EAAE,EAAE,iEAAiE;gBAChF,SAAS,GAAG,KAAK,CAAC;gBAClB,SAAS;aACV;YACD,IAAI,gBAAgB,CAAC,KAAK,CAAC,CAAC,OAAO,KAAK,MAAM,EAAE;gBAC [...]
\ No newline at end of file
+{"version":3,"file":"tobago-split-layout.js","sourceRoot":"../ts/","sources":["tobago-split-layout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,IAAI,EAAC,MAAM,eAAe,CAAC;AAEnC,MAAM,WAAY,SAAQ,WAAW;IAmBnC;QACE,KAAK,EAAE,CAAC;QAER,IAAI,KAAK,GAAG,IAAI,CAAC;QACjB,IAAI,SAAS,GAAG,KAAK,CAAC;QACtB,KAAK,IAAI,KAAK,IAAI,IAAI,CAAC,QAAQ,EAAE;YAC/B,IAAI,SAAS,EAAE,EAAE,iEAAiE;gBAChF,SAAS,GAAG,KAAK,CAAC;gBAClB,SAAS;aACV;YACD,IAAI,gBAAgB,CAAC,KAAK,CAAC,CAAC,OAAO,KAAK,MAAM,EAAE;gBAC9C, [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-stars.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-stars.js.map
index f944709..632c84c 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-stars.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-stars.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-stars.js","sourceRoot":"","sources":["../../ts/tobago-stars.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,MAAM,KAAM,SAAQ,WAAW;IAErB,MAAM,CAAC,UAAU,CAAC,OAAoB;QAC5C,IAAI,IAAI,GAAG,CAAC,CAAC;QAEb,IAAI,cAAc,GAAG,OAAO,CAAC;QAC7B,OAAO,cAAc,EAAE;YACrB,IAAI,IAAI,CAAC,cAAc,CAAC,UAAU,GAAG,cAAc,CAAC,UAAU,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;YAC5F,cAAc,GAAG,cAAc,CAAC,YAA2B,CAAC;SAC7D;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QACf,MA [...]
\ No newline at end of file
+{"version":3,"file":"tobago-stars.js","sourceRoot":"../ts/","sources":["tobago-stars.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,MAAM,KAAM,SAAQ,WAAW;IAErB,MAAM,CAAC,UAAU,CAAC,OAAoB;QAC5C,IAAI,IAAI,GAAG,CAAC,CAAC;QAEb,IAAI,cAAc,GAAG,OAAO,CAAC;QAC7B,OAAO,cAAc,EAAE;YACrB,IAAI,IAAI,CAAC,cAAc,CAAC,UAAU,GAAG,cAAc,CAAC,UAAU,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;YAC5F,cAAc,GAAG,cAAc,CAAC,YAA2B,CAAC;SAC7D;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QACf,MAAM, [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-suggest.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-suggest.js.map
index 854f8cc..c5f2d94 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-suggest.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-suggest.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-suggest.js","sourceRoot":"","sources":["../../ts/tobago-suggest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,YAAY,MAAM,6BAA6B,CAAC;AAEvD,MAAM,OAAO,OAAO;IAMlB,YAAY,QAAqB;QAC/B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAEM,IAAI;QACT,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;YACjB,OAAO,CAAC,IAAI,CAAC,gDAAgD,CAAC,CAAC;YAC/D,OAAO;SACR;QAED,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QACxC,IAAI,CAAC,IAAI,CAAC,kBAAkB,C [...]
\ No newline at end of file
+{"version":3,"file":"tobago-suggest.js","sourceRoot":"../ts/","sources":["tobago-suggest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,YAAY,MAAM,6BAA6B,CAAC;AAEvD,MAAM,OAAO,OAAO;IAMlB,YAAY,QAAqB;QAC/B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAEM,IAAI;QACT,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;YACjB,OAAO,CAAC,IAAI,CAAC,gDAAgD,CAAC,CAAC;YAC/D,OAAO;SACR;QAED,IAAI,CAAC,oBAAoB,EAAE,CAAC;QAC5B,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QACxC,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-tab.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-tab.js.map
index 65697ec..cbe5ef6 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-tab.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-tab.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-tab.js","sourceRoot":"","sources":["../../ts/tobago-tab.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,QAAS,SAAQ,WAAW;IAIhC;QACE,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,aAAa,CAAC,6BAA6B,CAAC,CAAC;IACvE,CAAC;IAED,iBAAiB;IACjB,CAAC;IAED,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC;IAC1C,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,gBAAgB,CAAC,wDAAwD,CAAoB,CAAC;IAC5G,CAAC;IAED,cAAc;QACZ,OAAO,IAAI,CAAC,aAAa,CACrB,gEAAgE,GAAG,IAAI,CAAC [...]
\ No newline at end of file
+{"version":3,"file":"tobago-tab.js","sourceRoot":"../ts/","sources":["tobago-tab.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,QAAS,SAAQ,WAAW;IAIhC;QACE,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,aAAa,CAAC,6BAA6B,CAAC,CAAC;IACvE,CAAC;IAED,iBAAiB;IACjB,CAAC;IAED,IAAI,UAAU;QACZ,OAAO,IAAI,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC;IAC1C,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,gBAAgB,CAAC,wDAAwD,CAAoB,CAAC;IAC5G,CAAC;IAED,cAAc;QACZ,OAAO,IAAI,CAAC,aAAa,CACrB,gEAAgE,GAAG,IAAI,CAAC,QA [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-textarea.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-textarea.js.map
index 9d45ced..b4b45e5 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-textarea.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-textarea.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-textarea.js","sourceRoot":"","sources":["../../ts/tobago-textarea.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAC,KAAK,EAAC,MAAM,gBAAgB,CAAC;AAErC,MAAM,QAAS,SAAQ,WAAW;IAChC;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;IAChE,CAAC;IAED,IAAI,QAAQ;QACV,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAA2B,CAAC;QAC7D,OAAO,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,GAAG,SAAS,CAAqB,CAAC;IAC1E,CAAC;CACF;AAE [...]
\ No newline at end of file
+{"version":3,"file":"tobago-textarea.js","sourceRoot":"../ts/","sources":["tobago-textarea.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAC,KAAK,EAAC,MAAM,gBAAgB,CAAC;AAErC,MAAM,QAAS,SAAQ,WAAW;IAChC;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,OAAO,EAAE,KAAK,CAAC,cAAc,CAAC,CAAC;IAChE,CAAC;IAED,IAAI,QAAQ;QACV,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAA2B,CAAC;QAC7D,OAAO,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,GAAG,SAAS,CAAqB,CAAC;IAC1E,CAAC;CACF;AAED,Q [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-tree-listbox.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-tree-listbox.js.map
index fb87696..35717e2 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-tree-listbox.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-tree-listbox.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-tree-listbox.js","sourceRoot":"","sources":["../../ts/tobago-tree-listbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,MAAM,WAAY,SAAQ,WAAW;IAEnC;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,aAAa,EAAE,CAAC;QAErB,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,SAAS,EAAE;YACpC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE;gBACrB,OAAO,CAAC,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;aAC5D;SACF;IACH,CAAC;IAEO,MAAM,CAAC,KAAY;QACzB,MAAM,OAAO,GAAG,KA [...]
\ No newline at end of file
+{"version":3,"file":"tobago-tree-listbox.js","sourceRoot":"../ts/","sources":["tobago-tree-listbox.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,MAAM,WAAY,SAAQ,WAAW;IAEnC;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,aAAa,EAAE,CAAC;QAErB,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,SAAS,EAAE;YACpC,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE;gBACrB,OAAO,CAAC,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;aAC5D;SACF;IACH,CAAC;IAEO,MAAM,CAAC,KAAY;QACzB,MAAM,OAAO,GAAG,KAAK, [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-tree-node.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-tree-node.js.map
index 90451cb..472533c 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-tree-node.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-tree-node.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-tree-node.js","sourceRoot":"","sources":["../../ts/tobago-tree-node.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,MAAM,OAAO,QAAS,SAAQ,WAAW;IAEvC;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QACf,IAAI,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,OAAO,KAAK,IAAI,EAAE;YAC5C,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;SAChG;IACH,CAAC;IAEO,UAAU,CAAC,KAAiB;QAClC,IAAI,IAAI,CAAC,QAAQ, [...]
\ No newline at end of file
+{"version":3,"file":"tobago-tree-node.js","sourceRoot":"../ts/","sources":["tobago-tree-node.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,MAAM,OAAO,QAAS,SAAQ,WAAW;IAEvC;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QACf,IAAI,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,OAAO,KAAK,IAAI,EAAE;YAC5C,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;SAChG;IACH,CAAC;IAEO,UAAU,CAAC,KAAiB;QAClC,IAAI,IAAI,CAAC,QAAQ,EAA [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-tree-select.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-tree-select.js.map
index 561f0da..ca85ff2 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-tree-select.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-tree-select.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-tree-select.js","sourceRoot":"","sources":["../../ts/tobago-tree-select.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,UAAU,EAAC,MAAM,qBAAqB,CAAC;AAI/C,MAAM,OAAO,UAAW,SAAQ,WAAW;IAEzC;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAChE,CAAC;IAED,MAAM,CAAC,KAAY;QACjB,QAAQ,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;YACvB,KAAK,OAAO;gBACV,IAAI,CAAC,IAAI,CAAC,kBAAkB,E [...]
\ No newline at end of file
+{"version":3,"file":"tobago-tree-select.js","sourceRoot":"../ts/","sources":["tobago-tree-select.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,UAAU,EAAC,MAAM,qBAAqB,CAAC;AAI/C,MAAM,OAAO,UAAW,SAAQ,WAAW;IAEzC;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;QACf,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAChE,CAAC;IAED,MAAM,CAAC,KAAY;QACjB,QAAQ,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;YACvB,KAAK,OAAO;gBACV,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-tree.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-tree.js.map
index dee2c68..a77ed2f 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-tree.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-tree.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-tree.js","sourceRoot":"","sources":["../../ts/tobago-tree.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,UAAU,EAAC,MAAM,qBAAqB,CAAC;AAG/C,MAAM,OAAO,IAAK,SAAQ,WAAW;IAEnC;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;IACjB,CAAC;IAED,kBAAkB;QAChB,IAAI,CAAC,mBAAmB,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,WAAW;IACpD,CAAC;IAED,eAAe,CAAC,YAAoB;QAClC,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC;QAC1E,aAAa,CAAC,GAAG,C [...]
\ No newline at end of file
+{"version":3,"file":"tobago-tree.js","sourceRoot":"../ts/","sources":["tobago-tree.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAC,UAAU,EAAC,MAAM,qBAAqB,CAAC;AAG/C,MAAM,OAAO,IAAK,SAAQ,WAAW;IAEnC;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED,iBAAiB;IACjB,CAAC;IAED,kBAAkB;QAChB,IAAI,CAAC,mBAAmB,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,WAAW;IACpD,CAAC;IAED,eAAe,CAAC,YAAoB;QAClC,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC;QAC1E,aAAa,CAAC,GAAG,CAAC [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-utils.js.map b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-utils.js.map
index 1ac234e..2c74c25 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-utils.js.map
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago-utils.js.map
@@ -1 +1 @@
-{"version":3,"file":"tobago-utils.js","sourceRoot":"","sources":["../../ts/tobago-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,6BAA6B;AAC7B,MAAM,OAAO,QAAQ;IAEnB;;;;OAIG;IACL,gFAAgF;IAC9E,MAAM,CAAC,sBAAsB,CAAC,OAAoB,EAAE,SAAiB;QACnE,MAAM,MAAM,GAAuB,IAAI,KAAK,EAAe,CAAC;QAC5D,IAAI,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE;YAC9B,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;SACtB;QACD,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,gBAAgB,CAAC,SAAS,CAAC,EAAE;YACvD,MAAM,CAAC,IAAI,CAAC,KAAoB,CAAC,CAAC;SACnC;QAC [...]
\ No newline at end of file
+{"version":3,"file":"tobago-utils.js","sourceRoot":"../ts/","sources":["tobago-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,6BAA6B;AAC7B,MAAM,OAAO,QAAQ;IAEnB;;;;OAIG;IACL,gFAAgF;IAC9E,MAAM,CAAC,sBAAsB,CAAC,OAAoB,EAAE,SAAiB;QACnE,MAAM,MAAM,GAAuB,IAAI,KAAK,EAAe,CAAC;QAC5D,IAAI,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE;YAC9B,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;SACtB;QACD,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,gBAAgB,CAAC,SAAS,CAAC,EAAE;YACvD,MAAM,CAAC,IAAI,CAAC,KAAoB,CAAC,CAAC;SACnC;QACD,O [...]
\ No newline at end of file
diff --git a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago.js b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago.js
index 4665b2b..26c82d4 100644
--- a/tobago-theme/tobago-theme-standard/npm/dist/js/tobago.js
+++ b/tobago-theme/tobago-theme-standard/npm/dist/js/tobago.js
@@ -1,1084 +1,1084 @@
 (function (factory) {
-    typeof define === 'function' && define.amd ? define(factory) :
-    factory();
+  typeof define === 'function' && define.amd ? define(factory) :
+  factory();
 }((function () { 'use strict';
 
-    /*
-     * Licensed to the Apache Software Foundation (ASF) under one or more
-     * contributor license agreements.  See the NOTICE file distributed with
-     * this work for additional information regarding copyright ownership.
-     * The ASF licenses this file to You under the Apache License, Version 2.0
-     * (the "License"); you may not use this file except in compliance with
-     * the License.  You may obtain a copy of the License at
-     *
-     *      http://www.apache.org/licenses/LICENSE-2.0
-     *
-     * Unless required by applicable law or agreed to in writing, software
-     * distributed under the License is distributed on an "AS IS" BASIS,
-     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     * See the License for the specific language governing permissions and
-     * limitations under the License.
-     */
-    var Phase;
-    (function (Phase) {
-        /** after the DOM was build */
-        Phase[Phase["DOCUMENT_READY"] = 0] = "DOCUMENT_READY";
-        /** after all images and CSS was loaded */
-        Phase[Phase["WINDOW_LOAD"] = 1] = "WINDOW_LOAD";
-        /** before sending a normal submit action */
-        Phase[Phase["BEFORE_SUBMIT"] = 2] = "BEFORE_SUBMIT";
-        /** after an AJAX call */
-        Phase[Phase["AFTER_UPDATE"] = 3] = "AFTER_UPDATE";
-        /** before ending a page */
-        Phase[Phase["BEFORE_UNLOAD"] = 4] = "BEFORE_UNLOAD";
-        /** before closing a window or tab */
-        Phase[Phase["BEFORE_EXIT"] = 5] = "BEFORE_EXIT";
-    })(Phase || (Phase = {}));
-    var Order;
-    (function (Order) {
-        Order[Order["EARLIER"] = 0] = "EARLIER";
-        Order[Order["EARLY"] = 1] = "EARLY";
-        Order[Order["NORMAL"] = 2] = "NORMAL";
-        Order[Order["LATE"] = 3] = "LATE";
-        Order[Order["LATER"] = 4] = "LATER";
-    })(Order || (Order = {}));
-    class ListenerList {
-        constructor() {
-            this.map = new Map([
-                [Order.EARLIER, []],
-                [Order.EARLY, []],
-                [Order.NORMAL, []],
-                [Order.LATE, []],
-                [Order.LATER, []]
-            ]);
-        }
-        add(listener, order) {
-            this.map.get(order).push(listener);
-        }
-        execute(element) {
-            this.map.forEach((listeners, order) => {
-                listeners.forEach((listener, index) => {
-                    console.time("[tobago] execute " + order + " " + index);
-                    listener(element);
-                    console.timeEnd("[tobago] execute " + order + " " + index);
-                });
-            });
-        }
-    }
-    class Listener {
-        /**
-         * Register a function to be executed on certain events.
-         * @param listener Function to be executed.
-         * @param phase The phase when code should be executed (e. g. Phase.DOCUMENT_READY).
-         * @param order An optional order to sort function they depend on others (default: Tobago.Order.NORMAL).
-         */
-        static register(listener, phase, order = Order.NORMAL) {
-            switch (phase) {
-                case Phase.DOCUMENT_READY:
-                    Listener.documentReady.add(listener, order);
-                    break;
-                case Phase.WINDOW_LOAD:
-                    Listener.windowLoad.add(listener, order);
-                    break;
-                case Phase.BEFORE_SUBMIT:
-                    Listener.beforeSubmit.add(listener, order);
-                    break;
-                case Phase.AFTER_UPDATE:
-                    Listener.afterUpdate.add(listener, order);
-                    break;
-                case Phase.BEFORE_UNLOAD:
-                    Listener.beforeUnload.add(listener, order);
-                    break;
-                case Phase.BEFORE_EXIT:
-                    Listener.beforeExit.add(listener, order);
-                    break;
-                default:
-                    console.error("Unknown phase: '" + phase + "'");
-            }
-        }
-        static executeDocumentReady(element) {
-            console.time("[tobago] execute documentReady");
-            Listener.documentReady.execute(element);
-            console.timeEnd("[tobago] execute documentReady");
-        }
-        static executeWindowLoad() {
-            console.time("[tobago] execute windowLoad");
-            Listener.windowLoad.execute();
-            console.timeEnd("[tobago] execute windowLoad");
-        }
-        static executeBeforeSubmit() {
-            console.time("[tobago] execute beforeSubmit");
-            Listener.beforeSubmit.execute();
-            console.timeEnd("[tobago] execute beforeSubmit");
-        }
-        static executeAfterUpdate(element) {
-            console.time("[tobago] execute afterUpdate");
-            Listener.afterUpdate.execute(element);
-            console.timeEnd("[tobago] execute afterUpdate");
-        }
-        static executeBeforeUnload() {
-            console.time("[tobago] execute beforeUnload");
-            Listener.beforeUnload.execute();
-            console.timeEnd("[tobago] execute beforeUnload");
-        }
-        static executeBeforeExit() {
-            console.time("[tobago] execute beforeExit");
-            Listener.beforeExit.execute();
-            console.timeEnd("[tobago] execute beforeExit");
-        }
-    }
-    // XXX check if "static" is nice
-    Listener.documentReady = new ListenerList();
-    Listener.windowLoad = new ListenerList();
-    Listener.beforeSubmit = new ListenerList();
-    Listener.afterUpdate = new ListenerList();
-    Listener.beforeUnload = new ListenerList();
-    Listener.beforeExit = new ListenerList();
-
-    /*
-     * Licensed to the Apache Software Foundation (ASF) under one or more
-     * contributor license agreements.  See the NOTICE file distributed with
-     * this work for additional information regarding copyright ownership.
-     * The ASF licenses this file to You under the Apache License, Version 2.0
-     * (the "License"); you may not use this file except in compliance with
-     * the License.  You may obtain a copy of the License at
-     *
-     *      http://www.apache.org/licenses/LICENSE-2.0
-     *
-     * Unless required by applicable law or agreed to in writing, software
-     * distributed under the License is distributed on an "AS IS" BASIS,
-     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     * See the License for the specific language governing permissions and
-     * limitations under the License.
-     */
-    // XXX remove me, for cleanup
-    class DomUtils {
-        /**
-         * Find all elements (and also self) which have the attribute "attributeName".
-         * @param element Starting element in DOM to collect.
-         * @param selectors Name of the attribute of the elements to find.
-         */
-        // todo: may return NodeListOf<HTMLElementTagNameMap[K]> or something like that.
-        static selfOrQuerySelectorAll(element, selectors) {
-            const result = new Array();
-            if (element.matches(selectors)) {
-                result.push(element);
-            }
-            for (const found of element.querySelectorAll(selectors)) {
-                result.push(found);
-            }
-            return result;
-        }
-        /**
-         * @param element with transition
-         * @return transition time in milliseconds
-         */
-        static getTransitionTime(element) {
-            const style = window.getComputedStyle(element);
-            let delay = Number.parseFloat(style.transitionDelay);
-            let duration = Number.parseFloat(style.transitionDuration);
-            return (delay + duration) * 1000;
-        }
-    }
-
-    /*
-     * Licensed to the Apache Software Foundation (ASF) under one or more
-     * contributor license agreements.  See the NOTICE file distributed with
-     * this work for additional information regarding copyright ownership.
-     * The ASF licenses this file to You under the Apache License, Version 2.0
-     * (the "License"); you may not use this file except in compliance with
-     * the License.  You may obtain a copy of the License at
-     *
-     *      http://www.apache.org/licenses/LICENSE-2.0
-     *
-     * Unless required by applicable law or agreed to in writing, software
-     * distributed under the License is distributed on an "AS IS" BASIS,
-     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     * See the License for the specific language governing permissions and
-     * limitations under the License.
-     */
-    class Bar extends HTMLElement {
-        constructor() {
-            super();
-            this.CssClass = {
-                SHOW: "show",
-                COLLAPSE: "collapse",
-                COLLAPSING: "collapsing"
-            };
-            this.ariaExpanded = "aria-expanded";
-            this.toggleButton.addEventListener("click", this.toggleCollapse.bind(this));
-        }
-        connectedCallback() {
-            this.expanded = this.toggleButton.getAttribute(this.ariaExpanded) === "true";
-        }
-        toggleCollapse(event) {
-            window.clearTimeout(this.timeout);
-            if (this.expanded) {
-                this.expanded = false;
-                this.navbarContent.style.height = this.navbarContent.scrollHeight + "px";
-                this.navbarContent.offsetHeight; //force reflow, to make sure height is set
-                this.navbarContent.classList.add(this.CssClass.COLLAPSING);
-                this.navbarContent.classList.remove(this.CssClass.COLLAPSE);
-                this.navbarContent.classList.remove(this.CssClass.SHOW);
-                this.navbarContent.style.height = null;
-                this.timeout = window.setTimeout(() => {
-                    this.navbarContent.classList.remove(this.CssClass.COLLAPSING);
-                    this.navbarContent.classList.add(this.CssClass.COLLAPSE);
-                    this.toggleButton.setAttribute(this.ariaExpanded, "false");
-                }, DomUtils.getTransitionTime(this.navbarContent));
-            }
-            else {
-                this.expanded = true;
-                this.navbarContent.classList.remove(this.CssClass.COLLAPSE);
-                this.navbarContent.classList.add(this.CssClass.COLLAPSING);
-                this.navbarContent.style.height = this.navbarContent.scrollHeight + "px";
-                this.timeout = window.setTimeout(() => {
-                    this.navbarContent.classList.remove(this.CssClass.COLLAPSING);
-                    this.navbarContent.classList.add(this.CssClass.COLLAPSE);
-                    this.navbarContent.classList.add(this.CssClass.SHOW);
-                    this.navbarContent.style.height = null;
-                    this.toggleButton.setAttribute(this.ariaExpanded, "true");
-                }, DomUtils.getTransitionTime(this.navbarContent));
-            }
-        }
-        get toggleButton() {
-            return this.querySelector(".navbar-toggler");
-        }
-        get navbarContent() {
-            return this.querySelector(".navbar-collapse");
-        }
-    }
-    document.addEventListener("tobago.init", function (event) {
-        if (window.customElements.get("tobago-bar") == null) {
-            window.customElements.define("tobago-bar", Bar);
-        }
+  /*
+   * Licensed to the Apache Software Foundation (ASF) under one or more
+   * contributor license agreements.  See the NOTICE file distributed with
+   * this work for additional information regarding copyright ownership.
+   * The ASF licenses this file to You under the Apache License, Version 2.0
+   * (the "License"); you may not use this file except in compliance with
+   * the License.  You may obtain a copy of the License at
+   *
+   *      http://www.apache.org/licenses/LICENSE-2.0
+   *
+   * Unless required by applicable law or agreed to in writing, software
+   * distributed under the License is distributed on an "AS IS" BASIS,
+   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   * See the License for the specific language governing permissions and
+   * limitations under the License.
+   */
+  var Phase;
+  (function (Phase) {
+      /** after the DOM was build */
+      Phase[Phase["DOCUMENT_READY"] = 0] = "DOCUMENT_READY";
+      /** after all images and CSS was loaded */
+      Phase[Phase["WINDOW_LOAD"] = 1] = "WINDOW_LOAD";
+      /** before sending a normal submit action */
+      Phase[Phase["BEFORE_SUBMIT"] = 2] = "BEFORE_SUBMIT";
+      /** after an AJAX call */
+      Phase[Phase["AFTER_UPDATE"] = 3] = "AFTER_UPDATE";
+      /** before ending a page */
+      Phase[Phase["BEFORE_UNLOAD"] = 4] = "BEFORE_UNLOAD";
+      /** before closing a window or tab */
+      Phase[Phase["BEFORE_EXIT"] = 5] = "BEFORE_EXIT";
+  })(Phase || (Phase = {}));
+  var Order;
+  (function (Order) {
+      Order[Order["EARLIER"] = 0] = "EARLIER";
+      Order[Order["EARLY"] = 1] = "EARLY";
+      Order[Order["NORMAL"] = 2] = "NORMAL";
+      Order[Order["LATE"] = 3] = "LATE";
+      Order[Order["LATER"] = 4] = "LATER";
+  })(Order || (Order = {}));
+  class ListenerList {
+      constructor() {
+          this.map = new Map([
+              [Order.EARLIER, []],
+              [Order.EARLY, []],
+              [Order.NORMAL, []],
+              [Order.LATE, []],
+              [Order.LATER, []]
+          ]);
+      }
+      add(listener, order) {
+          this.map.get(order).push(listener);
+      }
+      execute(element) {
+          this.map.forEach((listeners, order) => {
+              listeners.forEach((listener, index) => {
+                  console.time("[tobago] execute " + order + " " + index);
+                  listener(element);
+                  console.timeEnd("[tobago] execute " + order + " " + index);
+              });
+          });
+      }
+  }
+  class Listener {
+      /**
+       * Register a function to be executed on certain events.
+       * @param listener Function to be executed.
+       * @param phase The phase when code should be executed (e. g. Phase.DOCUMENT_READY).
+       * @param order An optional order to sort function they depend on others (default: Tobago.Order.NORMAL).
+       */
+      static register(listener, phase, order = Order.NORMAL) {
+          switch (phase) {
+              case Phase.DOCUMENT_READY:
+                  Listener.documentReady.add(listener, order);
+                  break;
+              case Phase.WINDOW_LOAD:
+                  Listener.windowLoad.add(listener, order);
+                  break;
+              case Phase.BEFORE_SUBMIT:
+                  Listener.beforeSubmit.add(listener, order);
+                  break;
+              case Phase.AFTER_UPDATE:
+                  Listener.afterUpdate.add(listener, order);
+                  break;
+              case Phase.BEFORE_UNLOAD:
+                  Listener.beforeUnload.add(listener, order);
+                  break;
+              case Phase.BEFORE_EXIT:
+                  Listener.beforeExit.add(listener, order);
+                  break;
+              default:
+                  console.error("Unknown phase: '" + phase + "'");
+          }
+      }
+      static executeDocumentReady(element) {
+          console.time("[tobago] execute documentReady");
+          Listener.documentReady.execute(element);
+          console.timeEnd("[tobago] execute documentReady");
+      }
+      static executeWindowLoad() {
+          console.time("[tobago] execute windowLoad");
+          Listener.windowLoad.execute();
+          console.timeEnd("[tobago] execute windowLoad");
+      }
+      static executeBeforeSubmit() {
+          console.time("[tobago] execute beforeSubmit");
+          Listener.beforeSubmit.execute();
+          console.timeEnd("[tobago] execute beforeSubmit");
+      }
+      static executeAfterUpdate(element) {
+          console.time("[tobago] execute afterUpdate");
+          Listener.afterUpdate.execute(element);
+          console.timeEnd("[tobago] execute afterUpdate");
+      }
+      static executeBeforeUnload() {
+          console.time("[tobago] execute beforeUnload");
+          Listener.beforeUnload.execute();
+          console.timeEnd("[tobago] execute beforeUnload");
+      }
+      static executeBeforeExit() {
+          console.time("[tobago] execute beforeExit");
+          Listener.beforeExit.execute();
+          console.timeEnd("[tobago] execute beforeExit");
+      }
+  }
+  // XXX check if "static" is nice
+  Listener.documentReady = new ListenerList();
+  Listener.windowLoad = new ListenerList();
+  Listener.beforeSubmit = new ListenerList();
+  Listener.afterUpdate = new ListenerList();
+  Listener.beforeUnload = new ListenerList();
+  Listener.beforeExit = new ListenerList();
+
+  /*
+   * Licensed to the Apache Software Foundation (ASF) under one or more
+   * contributor license agreements.  See the NOTICE file distributed with
+   * this work for additional information regarding copyright ownership.
+   * The ASF licenses this file to You under the Apache License, Version 2.0
+   * (the "License"); you may not use this file except in compliance with
+   * the License.  You may obtain a copy of the License at
+   *
+   *      http://www.apache.org/licenses/LICENSE-2.0
+   *
+   * Unless required by applicable law or agreed to in writing, software
+   * distributed under the License is distributed on an "AS IS" BASIS,
+   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   * See the License for the specific language governing permissions and
+   * limitations under the License.
+   */
+  // XXX remove me, for cleanup
+  class DomUtils {
+      /**
+       * Find all elements (and also self) which have the attribute "attributeName".
+       * @param element Starting element in DOM to collect.
+       * @param selectors Name of the attribute of the elements to find.
+       */
+      // todo: may return NodeListOf<HTMLElementTagNameMap[K]> or something like that.
+      static selfOrQuerySelectorAll(element, selectors) {
+          const result = new Array();
+          if (element.matches(selectors)) {
+              result.push(element);
+          }
+          for (const found of element.querySelectorAll(selectors)) {
+              result.push(found);
+          }
+          return result;
+      }
+      /**
+       * @param element with transition
+       * @return transition time in milliseconds
+       */
+      static getTransitionTime(element) {
+          const style = window.getComputedStyle(element);
+          let delay = Number.parseFloat(style.transitionDelay);
+          let duration = Number.parseFloat(style.transitionDuration);
+          return (delay + duration) * 1000;
+      }
+  }
+
+  /*
+   * Licensed to the Apache Software Foundation (ASF) under one or more
+   * contributor license agreements.  See the NOTICE file distributed with
+   * this work for additional information regarding copyright ownership.
+   * The ASF licenses this file to You under the Apache License, Version 2.0
+   * (the "License"); you may not use this file except in compliance with
+   * the License.  You may obtain a copy of the License at
+   *
+   *      http://www.apache.org/licenses/LICENSE-2.0
+   *
+   * Unless required by applicable law or agreed to in writing, software
+   * distributed under the License is distributed on an "AS IS" BASIS,
+   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   * See the License for the specific language governing permissions and
+   * limitations under the License.
+   */
+  class Bar extends HTMLElement {
+      constructor() {
+          super();
+          this.CssClass = {
+              SHOW: "show",
+              COLLAPSE: "collapse",
+              COLLAPSING: "collapsing"
+          };
+          this.ariaExpanded = "aria-expanded";
+          this.toggleButton.addEventListener("click", this.toggleCollapse.bind(this));
+      }
+      connectedCallback() {
+          this.expanded = this.toggleButton.getAttribute(this.ariaExpanded) === "true";
+      }
+      toggleCollapse(event) {
+          window.clearTimeout(this.timeout);
+          if (this.expanded) {
+              this.expanded = false;
+              this.navbarContent.style.height = this.navbarContent.scrollHeight + "px";
+              this.navbarContent.offsetHeight; //force reflow, to make sure height is set
+              this.navbarContent.classList.add(this.CssClass.COLLAPSING);
+              this.navbarContent.classList.remove(this.CssClass.COLLAPSE);
+              this.navbarContent.classList.remove(this.CssClass.SHOW);
+              this.navbarContent.style.height = null;
+              this.timeout = window.setTimeout(() => {
+                  this.navbarContent.classList.remove(this.CssClass.COLLAPSING);
+                  this.navbarContent.classList.add(this.CssClass.COLLAPSE);
+                  this.toggleButton.setAttribute(this.ariaExpanded, "false");
+              }, DomUtils.getTransitionTime(this.navbarContent));
+          }
+          else {
+              this.expanded = true;
+              this.navbarContent.classList.remove(this.CssClass.COLLAPSE);
+              this.navbarContent.classList.add(this.CssClass.COLLAPSING);
+              this.navbarContent.style.height = this.navbarContent.scrollHeight + "px";
+              this.timeout = window.setTimeout(() => {
+                  this.navbarContent.classList.remove(this.CssClass.COLLAPSING);
+                  this.navbarContent.classList.add(this.CssClass.COLLAPSE);
+                  this.navbarContent.classList.add(this.CssClass.SHOW);
+                  this.navbarContent.style.height = null;
+                  this.toggleButton.setAttribute(this.ariaExpanded, "true");
+              }, DomUtils.getTransitionTime(this.navbarContent));
+          }
+      }
+      get toggleButton() {
+          return this.querySelector(".navbar-toggler");
+      }
+      get navbarContent() {
+          return this.querySelector(".navbar-collapse");
+      }
+  }
+  document.addEventListener("tobago.init", function (event) {
+      if (window.customElements.get("tobago-bar") == null) {
+          window.customElements.define("tobago-bar", Bar);
+      }
+  });
+
+  /*
+   * Licensed to the Apache Software Foundation (ASF) under one or more
+   * contributor license agreements.  See the NOTICE file distributed with
+   * this work for additional information regarding copyright ownership.
+   * The ASF licenses this file to You under the Apache License, Version 2.0
+   * (the "License"); you may not use this file except in compliance with
+   * the License.  You may obtain a copy of the License at
+   *
+   *      http://www.apache.org/licenses/LICENSE-2.0
+   *
+   * Unless required by applicable law or agreed to in writing, software
+   * distributed under the License is distributed on an "AS IS" BASIS,
+   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   * See the License for the specific language governing permissions and
+   * limitations under the License.
+   */
+  const TobagoDropdownEvent = {
+      HIDE: "tobago.dropdown.hide",
+      HIDDEN: "tobago.dropdown.hidden",
+      SHOW: "tobago.dropdown.show",
+      SHOWN: "tobago.dropdown.shown"
+  };
+  /**
+   * The dropdown implementation of Bootstrap does not move the menu to the tobago-page-menuStore. This behavior is
+   * implemented in this class.
+   */
+  class Dropdown extends HTMLElement {
+      constructor() {
+          super();
+          if (!this.classList.contains("tobago-dropdown-submenu")) { // ignore submenus
+              this.addEventListener("shown.bs.dropdown", this.openDropdown.bind(this));
+              this.addEventListener("hidden.bs.dropdown", this.closeDropdown.bind(this));
+          }
+      }
+      connectedCallback() {
+      }
+      openDropdown() {
+          this.dispatchEvent(new CustomEvent(TobagoDropdownEvent.SHOW));
+          if (!this.inStickyHeader()) {
+              this.menuStore.appendChild(this.dropdownMenu);
+          }
+          this.dispatchEvent(new CustomEvent(TobagoDropdownEvent.SHOWN));
+      }
+      closeDropdown() {
+          this.dispatchEvent(new CustomEvent(TobagoDropdownEvent.HIDE));
+          if (!this.inStickyHeader()) {
+              this.appendChild(this.dropdownMenu);
+          }
+          this.dispatchEvent(new CustomEvent(TobagoDropdownEvent.HIDDEN));
+      }
+      inStickyHeader() {
+          return Boolean(this.closest("tobago-header.sticky-top"));
+      }
+      get dropdownMenu() {
+          const root = this.getRootNode();
+          return root.querySelector(".dropdown-menu[name='" + this.id + "']");
+      }
+      get menuStore() {
+          const root = this.getRootNode();
+          return root.querySelector(".tobago-page-menuStore");
+      }
+  }
+  document.addEventListener("tobago.init", function (event) {
+      if (window.customElements.get("tobago-dropdown") == null) {
+          window.customElements.define("tobago-dropdown", Dropdown);
+      }
+  });
+
+  function hasProperty(obj, prop) {
+    return Object.prototype.hasOwnProperty.call(obj, prop);
+  }
+
+  function lastItemOf(arr) {
+    return arr[arr.length - 1];
+  }
+
+  // push only the items not included in the array
+  function pushUnique(arr, ...items) {
+    items.forEach((item) => {
+      if (arr.includes(item)) {
+        return;
+      }
+      arr.push(item);
     });
+    return arr;
+  }
+
+  function stringToArray(str, separator) {
+    // convert empty string to an empty array
+    return str ? str.split(separator) : [];
+  }
+
+  function isInRange(testVal, min, max) {
+    const minOK = min === undefined || testVal >= min;
+    const maxOK = max === undefined || testVal <= max;
+    return minOK && maxOK;
+  }
+
+  function limitToRange(val, min, max) {
+    if (val < min) {
+      return min;
+    }
+    if (val > max) {
+      return max;
+    }
+    return val;
+  }
+
+  function createTagRepeat(tagName, repeat, attributes = {}, index = 0, html = '') {
+    const openTagSrc = Object.keys(attributes).reduce((src, attr) => {
+      let val = attributes[attr];
+      if (typeof val === 'function') {
+        val = val(index);
+      }
+      return `${src} ${attr}="${val}"`;
+    }, tagName);
+    html += `<${openTagSrc}></${tagName}>`;
+
+    const next = index + 1;
+    return next < repeat
+      ? createTagRepeat(tagName, repeat, attributes, next, html)
+      : html;
+  }
+
+  // Remove the spacing surrounding tags for HTML parser not to create text nodes
+  // before/after elements
+  function optimizeTemplateHTML(html) {
+    return html.replace(/>\s+/g, '>').replace(/\s+</, '<');
+  }
+
+  function stripTime(timeValue) {
+    return new Date(timeValue).setHours(0, 0, 0, 0);
+  }
+
+  function today() {
+    return new Date().setHours(0, 0, 0, 0);
+  }
+
+  // Get the time value of the start of given date or year, month and day
+  function dateValue(...args) {
+    switch (args.length) {
+      case 0:
+        return today();
+      case 1:
+        return stripTime(args[0]);
+    }
+
+    // use setFullYear() to keep 2-digit year from being mapped to 1900-1999
+    const newDate = new Date(0);
+    newDate.setFullYear(...args);
+    return newDate.setHours(0, 0, 0, 0);
+  }
+
+  function addDays(date, amount) {
+    const newDate = new Date(date);
+    return newDate.setDate(newDate.getDate() + amount);
+  }
+
+  function addWeeks(date, amount) {
+    return addDays(date, amount * 7);
+  }
+
+  function addMonths(date, amount) {
+    // If the day of the date is not in the new month, the last day of the new
+    // month will be returned. e.g. Jan 31 + 1 month → Feb 28 (not Mar 03)
+    const newDate = new Date(date);
+    const monthsToSet = newDate.getMonth() + amount;
+    let expectedMonth = monthsToSet % 12;
+    if (expectedMonth < 0) {
+      expectedMonth += 12;
+    }
+
+    const time = newDate.setMonth(monthsToSet);
+    return newDate.getMonth() !== expectedMonth ? newDate.setDate(0) : time;
+  }
+
+  function addYears(date, amount) {
+    // If the date is Feb 29 and the new year is not a leap year, Feb 28 of the
+    // new year will be returned.
+    const newDate = new Date(date);
+    const expectedMonth = newDate.getMonth();
+    const time = newDate.setFullYear(newDate.getFullYear() + amount);
+    return expectedMonth === 1 && newDate.getMonth() === 2 ? newDate.setDate(0) : time;
+  }
+
+  // Calculate the distance bettwen 2 days of the week
+  function dayDiff(day, from) {
+    return (day - from + 7) % 7;
+  }
+
+  // Get the date of the specified day of the week of given base date
+  function dayOfTheWeekOf(baseDate, dayOfWeek, weekStart = 0) {
+    const baseDay = new Date(baseDate).getDay();
+    return addDays(baseDate, dayDiff(dayOfWeek, weekStart) - dayDiff(baseDay, weekStart));
+  }
+
+  // Get the ISO week of a date
+  function getWeek(date) {
+    // start of ISO week is Monday
+    const thuOfTheWeek = dayOfTheWeekOf(date, 4, 1);
+    // 1st week == the week where the 4th of January is in
+    const firstThu = dayOfTheWeekOf(new Date(thuOfTheWeek).setMonth(0, 4), 4, 1);
+    return Math.round((thuOfTheWeek - firstThu) / 604800000) + 1;
+  }
+
+  // Get the start year of the period of years that includes given date
+  // years: length of the year period
+  function startOfYearPeriod(date, years) {
+    /* @see https://en.wikipedia.org/wiki/Year_zero#ISO_8601 */
+    const year = new Date(date).getFullYear();
+    return Math.floor(year / years) * years;
+  }
+
+  // pattern for format parts
+  const reFormatTokens = /dd?|DD?|mm?|MM?|yy?(?:yy)?/;
+  // pattern for non date parts
+  const reNonDateParts = /[\s!-/:-@[-`{-~年月日]+/;
+  // cache for persed formats
+  let knownFormats = {};
+  // parse funtions for date parts
+  const parseFns = {
+    y(date, year) {
+      return new Date(date).setFullYear(parseInt(year, 10));
+    },
+    m(date, month, locale) {
+      const newDate = new Date(date);
+      let monthIndex = parseInt(month, 10) - 1;
+
+      if (isNaN(monthIndex)) {
+        if (!month) {
+          return NaN;
+        }
+
+        const monthName = month.toLowerCase();
+        const compareNames = name => name.toLowerCase().startsWith(monthName);
+        // compare with both short and full names because some locales have periods
+        // in the short names (not equal to the first X letters of the full names)
+        monthIndex = locale.monthsShort.findIndex(compareNames);
+        if (monthIndex < 0) {
+          monthIndex = locale.months.findIndex(compareNames);
+        }
+        if (monthIndex < 0) {
+          return NaN;
+        }
+      }
+
+      newDate.setMonth(monthIndex);
+      return newDate.getMonth() !== normalizeMonth(monthIndex)
+        ? newDate.setDate(0)
+        : newDate.getTime();
+    },
+    d(date, day) {
+      return new Date(date).setDate(parseInt(day, 10));
+    },
+  };
+  // format functions for date parts
+  const formatFns = {
+    d(date) {
+      return date.getDate();
+    },
+    dd(date) {
+      return padZero(date.getDate(), 2);
+    },
+    D(date, locale) {
+      return locale.daysShort[date.getDay()];
+    },
+    DD(date, locale) {
+      return locale.days[date.getDay()];
+    },
+    m(date) {
+      return date.getMonth() + 1;
+    },
+    mm(date) {
+      return padZero(date.getMonth() + 1, 2);
+    },
+    M(date, locale) {
+      return locale.monthsShort[date.getMonth()];
+    },
+    MM(date, locale) {
+      return locale.months[date.getMonth()];
+    },
+    y(date) {
+      return date.getFullYear();
+    },
+    yy(date) {
+      return padZero(date.getFullYear(), 2).slice(-2);
+    },
+    yyyy(date) {
+      return padZero(date.getFullYear(), 4);
+    },
+  };
+
+  // get month index in normal range (0 - 11) from any number
+  function normalizeMonth(monthIndex) {
+    return monthIndex > -1 ? monthIndex % 12 : normalizeMonth(monthIndex + 12);
+  }
+
+  function padZero(num, length) {
+    return num.toString().padStart(length, '0');
+  }
+
+  function parseFormatString(format) {
+    if (typeof format !== 'string') {
+      throw new Error("Invalid date format.");
+    }
+    if (format in knownFormats) {
+      return knownFormats[format];
+    }
+
+    // sprit the format string into parts and seprators
+    const separators = format.split(reFormatTokens);
+    const parts = format.match(new RegExp(reFormatTokens, 'g'));
+    if (separators.length === 0 || !parts) {
+      throw new Error("Invalid date format.");
+    }
+
+    // collect format functions used in the format
+    const partFormatters = parts.map(token => formatFns[token]);
+
+    // collect parse function keys used in the format
+    // iterate over parseFns' keys in order to keep the order of the keys.
+    const partParserKeys = Object.keys(parseFns).reduce((keys, key) => {
+      const token = parts.find(part => part[0] !== 'D' && part[0].toLowerCase() === key);
+      if (token) {
+        keys.push(key);
+      }
+      return keys;
+    }, []);
 
-    /*
-     * Licensed to the Apache Software Foundation (ASF) under one or more
-     * contributor license agreements.  See the NOTICE file distributed with
-     * this work for additional information regarding copyright ownership.
-     * The ASF licenses this file to You under the Apache License, Version 2.0
-     * (the "License"); you may not use this file except in compliance with
-     * the License.  You may obtain a copy of the License at
-     *
-     *      http://www.apache.org/licenses/LICENSE-2.0
-     *
-     * Unless required by applicable law or agreed to in writing, software
-     * distributed under the License is distributed on an "AS IS" BASIS,
-     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     * See the License for the specific language governing permissions and
-     * limitations under the License.
-     */
-    const TobagoDropdownEvent = {
-        HIDE: "tobago.dropdown.hide",
-        HIDDEN: "tobago.dropdown.hidden",
-        SHOW: "tobago.dropdown.show",
-        SHOWN: "tobago.dropdown.shown"
-    };
-    /**
-     * The dropdown implementation of Bootstrap does not move the menu to the tobago-page-menuStore. This behavior is
-     * implemented in this class.
-     */
-    class Dropdown extends HTMLElement {
-        constructor() {
-            super();
-            if (!this.classList.contains("tobago-dropdown-submenu")) { // ignore submenus
-                this.addEventListener("shown.bs.dropdown", this.openDropdown.bind(this));
-                this.addEventListener("hidden.bs.dropdown", this.closeDropdown.bind(this));
-            }
-        }
-        connectedCallback() {
-        }
-        openDropdown() {
-            this.dispatchEvent(new CustomEvent(TobagoDropdownEvent.SHOW));
-            if (!this.inStickyHeader()) {
-                this.menuStore.appendChild(this.dropdownMenu);
+    return knownFormats[format] = {
+      parser(dateStr, locale) {
+        const dateParts = dateStr.split(reNonDateParts).reduce((dtParts, part, index) => {
+          if (part.length > 0 && parts[index]) {
+            const token = parts[index][0];
+            if (token === 'M') {
+              dtParts.m = part;
+            } else if (token !== 'D') {
+              dtParts[token] = part;
             }
-            this.dispatchEvent(new CustomEvent(TobagoDropdownEvent.SHOWN));
-        }
-        closeDropdown() {
-            this.dispatchEvent(new CustomEvent(TobagoDropdownEvent.HIDE));
-            if (!this.inStickyHeader()) {
-                this.appendChild(this.dropdownMenu);
-            }
-            this.dispatchEvent(new CustomEvent(TobagoDropdownEvent.HIDDEN));
-        }
-        inStickyHeader() {
-            return Boolean(this.closest("tobago-header.sticky-top"));
-        }
-        get dropdownMenu() {
-            const root = this.getRootNode();
-            return root.querySelector(".dropdown-menu[name='" + this.id + "']");
-        }
-        get menuStore() {
-            const root = this.getRootNode();
-            return root.querySelector(".tobago-page-menuStore");
-        }
-    }
-    document.addEventListener("tobago.init", function (event) {
-        if (window.customElements.get("tobago-dropdown") == null) {
-            window.customElements.define("tobago-dropdown", Dropdown);
-        }
-    });
-
-    function hasProperty(obj, prop) {
-      return Object.prototype.hasOwnProperty.call(obj, prop);
-    }
-
-    function lastItemOf(arr) {
-      return arr[arr.length - 1];
-    }
-
-    // push only the items not included in the array
-    function pushUnique(arr, ...items) {
-      items.forEach((item) => {
-        if (arr.includes(item)) {
-          return;
-        }
-        arr.push(item);
-      });
-      return arr;
-    }
-
-    function stringToArray(str, separator) {
-      // convert empty string to an empty array
-      return str ? str.split(separator) : [];
-    }
-
-    function isInRange(testVal, min, max) {
-      const minOK = min === undefined || testVal >= min;
-      const maxOK = max === undefined || testVal <= max;
-      return minOK && maxOK;
-    }
-
-    function limitToRange(val, min, max) {
-      if (val < min) {
-        return min;
-      }
-      if (val > max) {
-        return max;
-      }
-      return val;
-    }
+          }
+          return dtParts;
+        }, {});
 
-    function createTagRepeat(tagName, repeat, attributes = {}, index = 0, html = '') {
-      const openTagSrc = Object.keys(attributes).reduce((src, attr) => {
-        let val = attributes[attr];
-        if (typeof val === 'function') {
-          val = val(index);
-        }
-        return `${src} ${attr}="${val}"`;
-      }, tagName);
-      html += `<${openTagSrc}></${tagName}>`;
+        // iterate over partParserkeys so that the parsing is made in the oder
+        // of year, month and day to prevent the day parser from correcting last
+        // day of month wrongly
+        return partParserKeys.reduce((origDate, key) => {
+          const newDate = parseFns[key](origDate, dateParts[key], locale);
+          // ingnore the part failed to parse
+          return isNaN(newDate) ? origDate : newDate;
+        }, today());
+      },
+      formatter(date, locale) {
+        let dateStr = partFormatters.reduce((str, fn, index) => {
+          return str += `${separators[index]}${fn(date, locale)}`;
+        }, '');
+        // separators' length is always parts' length + 1,
+        return dateStr += lastItemOf(separators);
+      },
+    };
+  }
 
-      const next = index + 1;
-      return next < repeat
-        ? createTagRepeat(tagName, repeat, attributes, next, html)
-        : html;
+  function parseDate(dateStr, format, locale) {
+    if (dateStr instanceof Date || typeof dateStr === 'number') {
+      const date = stripTime(dateStr);
+      return isNaN(date) ? undefined : date;
     }
-
-    // Remove the spacing surrounding tags for HTML parser not to create text nodes
-    // before/after elements
-    function optimizeTemplateHTML(html) {
-      return html.replace(/>\s+/g, '>').replace(/\s+</, '<');
+    if (!dateStr) {
+      return undefined;
     }
-
-    function stripTime(timeValue) {
-      return new Date(timeValue).setHours(0, 0, 0, 0);
+    if (dateStr === 'today') {
+      return today();
     }
 
-    function today() {
-      return new Date().setHours(0, 0, 0, 0);
+    if (format && format.toValue) {
+      const date = format.toValue(dateStr, format, locale);
+      return isNaN(date) ? undefined : stripTime(date);
     }
 
-    // Get the time value of the start of given date or year, month and day
-    function dateValue(...args) {
-      switch (args.length) {
-        case 0:
-          return today();
-        case 1:
-          return stripTime(args[0]);
-      }
+    return parseFormatString(format).parser(dateStr, locale);
+  }
 
-      // use setFullYear() to keep 2-digit year from being mapped to 1900-1999
-      const newDate = new Date(0);
-      newDate.setFullYear(...args);
-      return newDate.setHours(0, 0, 0, 0);
+  function formatDate(date, format, locale) {
+    if (isNaN(date) || (!date && date !== 0)) {
+      return '';
     }
 
-    function addDays(date, amount) {
-      const newDate = new Date(date);
-      return newDate.setDate(newDate.getDate() + amount);
-    }
+    const dateObj = typeof date === 'number' ? new Date(date) : date;
 
-    function addWeeks(date, amount) {
-      return addDays(date, amount * 7);
+    if (format.toDisplay) {
+      return format.toDisplay(dateObj, format, locale);
     }
 
-    function addMonths(date, amount) {
-      // If the day of the date is not in the new month, the last day of the new
-      // month will be returned. e.g. Jan 31 + 1 month → Feb 28 (not Mar 03)
-      const newDate = new Date(date);
-      const monthsToSet = newDate.getMonth() + amount;
-      let expectedMonth = monthsToSet % 12;
-      if (expectedMonth < 0) {
-        expectedMonth += 12;
-      }
-
-      const time = newDate.setMonth(monthsToSet);
-      return newDate.getMonth() !== expectedMonth ? newDate.setDate(0) : time;
-    }
+    return parseFormatString(format).formatter(dateObj, locale);
+  }
 
-    function addYears(date, amount) {
-      // If the date is Feb 29 and the new year is not a leap year, Feb 28 of the
-      // new year will be returned.
-      const newDate = new Date(date);
-      const expectedMonth = newDate.getMonth();
-      const time = newDate.setFullYear(newDate.getFullYear() + amount);
-      return expectedMonth === 1 && newDate.getMonth() === 2 ? newDate.setDate(0) : time;
-    }
+  const listenerRegistry = new WeakMap();
+  const {addEventListener, removeEventListener} = EventTarget.prototype;
 
-    // Calculate the distance bettwen 2 days of the week
-    function dayDiff(day, from) {
-      return (day - from + 7) % 7;
+  // Register event listeners to a key object
+  // listeners: array of listener definitions;
+  //   - each definition must be a flat array of event target and the arguments
+  //     used to call addEventListener() on the target
+  function registerListeners(keyObj, listeners) {
+    let registered = listenerRegistry.get(keyObj);
+    if (!registered) {
+      registered = [];
+      listenerRegistry.set(keyObj, registered);
     }
+    listeners.forEach((listener) => {
+      addEventListener.call(...listener);
+      registered.push(listener);
+    });
+  }
 
-    // Get the date of the specified day of the week of given base date
-    function dayOfTheWeekOf(baseDate, dayOfWeek, weekStart = 0) {
-      const baseDay = new Date(baseDate).getDay();
-      return addDays(baseDate, dayDiff(dayOfWeek, weekStart) - dayDiff(baseDay, weekStart));
+  function unregisterListeners(keyObj) {
+    let listeners = listenerRegistry.get(keyObj);
+    if (!listeners) {
+      return;
     }
+    listeners.forEach((listener) => {
+      removeEventListener.call(...listener);
+    });
+    listenerRegistry.delete(keyObj);
+  }
+
+  // Event.composedPath() polyfill for Edge
+  // based on https://gist.github.com/kleinfreund/e9787d73776c0e3750dcfcdc89f100ec
+  if (!Event.prototype.composedPath) {
+    const getComposedPath = (node, path = []) => {
+      path.push(node);
+
+      let parent;
+      if (node.parentNode) {
+        parent = node.parentNode;
+      } else if (node.host) { // ShadowRoot
+        parent = node.host;
+      } else if (node.defaultView) {  // Document
+        parent = node.defaultView;
+      }
+      return parent ? getComposedPath(parent, path) : path;
+    };
 
-    // Get the ISO week of a date
-    function getWeek(date) {
-      // start of ISO week is Monday
-      const thuOfTheWeek = dayOfTheWeekOf(date, 4, 1);
-      // 1st week == the week where the 4th of January is in
-      const firstThu = dayOfTheWeekOf(new Date(thuOfTheWeek).setMonth(0, 4), 4, 1);
-      return Math.round((thuOfTheWeek - firstThu) / 604800000) + 1;
+    Event.prototype.composedPath = function () {
+      return getComposedPath(this.target);
+    };
+  }
+
+  function findFromPath(path, criteria, currentTarget, index = 0) {
+    const el = path[index];
+    if (criteria(el)) {
+      return el;
+    } else if (el === currentTarget || !el.parentElement) {
+      // stop when reaching currentTarget or <html>
+      return;
+    }
+    return findFromPath(path, criteria, currentTarget, index + 1);
+  }
+
+  // Search for the actual target of a delegated event
+  function findElementInEventPath(ev, selector) {
+    const criteria = typeof selector === 'function' ? selector : el => el.matches(selector);
+    return findFromPath(ev.composedPath(), criteria, ev.currentTarget);
+  }
+
+  // default locales
+  const locales = {
+    en: {
+      days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
+      daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+      daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
+      months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
+      monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+      today: "Today",
+      clear: "Clear",
+      titleFormat: "MM y"
+    }
+  };
+
+  // config options updatable by setOptions() and their default values
+  const defaultOptions = {
+    autohide: false,
+    beforeShowDay: null,
+    beforeShowDecade: null,
+    beforeShowMonth: null,
+    beforeShowYear: null,
+    calendarWeeks: false,
+    clearBtn: false,
+    dateDelimiter: ',',
+    datesDisabled: [],
+    daysOfWeekDisabled: [],
+    daysOfWeekHighlighted: [],
+    defaultViewDate: undefined, // placeholder, defaults to today() by the program
+    disableTouchKeyboard: false,
+    format: 'mm/dd/yyyy',
+    language: 'en',
+    maxDate: null,
+    maxNumberOfDates: 1,
+    maxView: 3,
+    minDate: null,
+    nextArrow: '»',
+    orientation: 'auto',
+    pickLevel: 0,
+    prevArrow: '«',
+    showDaysOfWeek: true,
+    showOnClick: true,
+    showOnFocus: true,
+    startView: 0,
+    title: '',
+    todayBtn: false,
+    todayBtnMode: 0,
+    todayHighlight: false,
+    updateOnBlur: true,
+    weekStart: 0,
+  };
+
+  const range = document.createRange();
+
+  function parseHTML(html) {
+    return range.createContextualFragment(html);
+  }
+
+  function hideElement(el) {
+    if (el.style.display === 'none') {
+      return;
+    }
+    // back up the existing display setting in data-style-display
+    if (el.style.display) {
+      el.dataset.styleDisplay = el.style.display;
+    }
+    el.style.display = 'none';
+  }
+
+  function showElement(el) {
+    if (el.style.display !== 'none') {
+      return;
+    }
+    if (el.dataset.styleDisplay) {
+      // restore backed-up dispay property
+      el.style.display = el.dataset.styleDisplay;
+      delete el.dataset.styleDisplay;
+    } else {
+      el.style.display = '';
+    }
+  }
+
+  function emptyChildNodes(el) {
+    if (el.firstChild) {
+      el.removeChild(el.firstChild);
+      emptyChildNodes(el);
     }
-
-    // Get the start year of the period of years that includes given date
-    // years: length of the year period
-    function startOfYearPeriod(date, years) {
-      /* @see https://en.wikipedia.org/wiki/Year_zero#ISO_8601 */
-      const year = new Date(date).getFullYear();
-      return Math.floor(year / years) * years;
+  }
+
+  function replaceChildNodes(el, newChildNodes) {
+    emptyChildNodes(el);
+    if (newChildNodes instanceof DocumentFragment) {
+      el.appendChild(newChildNodes);
+    } else if (typeof newChildNodes === 'string') {
+      el.appendChild(parseHTML(newChildNodes));
+    } else if (typeof newChildNodes.forEach === 'function') {
+      newChildNodes.forEach((node) => {
+        el.appendChild(node);
+      });
     }
-
-    // pattern for format parts
-    const reFormatTokens = /dd?|DD?|mm?|MM?|yy?(?:yy)?/;
-    // pattern for non date parts
-    const reNonDateParts = /[\s!-/:-@[-`{-~年月日]+/;
-    // cache for persed formats
-    let knownFormats = {};
-    // parse funtions for date parts
-    const parseFns = {
-      y(date, year) {
-        return new Date(date).setFullYear(parseInt(year, 10));
-      },
-      m(date, month, locale) {
-        const newDate = new Date(date);
-        let monthIndex = parseInt(month, 10) - 1;
-
-        if (isNaN(monthIndex)) {
-          if (!month) {
-            return NaN;
-          }
-
-          const monthName = month.toLowerCase();
-          const compareNames = name => name.toLowerCase().startsWith(monthName);
-          // compare with both short and full names because some locales have periods
-          // in the short names (not equal to the first X letters of the full names)
-          monthIndex = locale.monthsShort.findIndex(compareNames);
-          if (monthIndex < 0) {
-            monthIndex = locale.months.findIndex(compareNames);
-          }
-          if (monthIndex < 0) {
-            return NaN;
+  }
+
+  const {
+    language: defaultLang,
+    format: defaultFormat,
+    weekStart: defaultWeekStart,
+  } = defaultOptions;
+
+  // Reducer function to filter out invalid day-of-week from the input
+  function sanitizeDOW(dow, day) {
+    return dow.length < 6 && day >= 0 && day < 7
+      ? pushUnique(dow, day)
+      : dow;
+  }
+
+  function calcEndOfWeek(startOfWeek) {
+    return (startOfWeek + 6) % 7;
+  }
+
+  // validate input date. if invalid, fallback to the original value
+  function validateDate(value, format, locale, origValue) {
+    const date = parseDate(value, format, locale);
+    return date !== undefined ? date : origValue;
+  }
+
+  // Validate viewId. if invalid, fallback to the original value
+  function validateViewId(value, origValue, max = 3) {
+    const viewId = parseInt(value, 10);
+    return viewId >= 0 && viewId <= max ? viewId : origValue;
+  }
+
+  // Create Datepicker configuration to set
+  function processOptions(options, datepicker) {
+    const inOpts = Object.assign({}, options);
+    const config = {};
+    const locales = datepicker.constructor.locales;
+    let {
+      format,
+      language,
+      locale,
+      maxDate,
+      maxView,
+      minDate,
+      pickLevel,
+      startView,
+      weekStart,
+    } = datepicker.config || {};
+
+    if (inOpts.language) {
+      let lang;
+      if (inOpts.language !== language) {
+        if (locales[inOpts.language]) {
+          lang = inOpts.language;
+        } else {
+          // Check if langauge + region tag can fallback to the one without
+          // region (e.g. fr-CA → fr)
+          lang = inOpts.language.split('-')[0];
+          if (locales[lang] === undefined) {
+            lang = false;
           }
         }
-
-        newDate.setMonth(monthIndex);
-        return newDate.getMonth() !== normalizeMonth(monthIndex)
-          ? newDate.setDate(0)
-          : newDate.getTime();
-      },
-      d(date, day) {
-        return new Date(date).setDate(parseInt(day, 10));
-      },
-    };
-    // format functions for date parts
-    const formatFns = {
-      d(date) {
-        return date.getDate();
-      },
-      dd(date) {
-        return padZero(date.getDate(), 2);
-      },
-      D(date, locale) {
-        return locale.daysShort[date.getDay()];
-      },
-      DD(date, locale) {
-        return locale.days[date.getDay()];
-      },
-      m(date) {
-        return date.getMonth() + 1;
-      },
-      mm(date) {
-        return padZero(date.getMonth() + 1, 2);
-      },
-      M(date, locale) {
-        return locale.monthsShort[date.getMonth()];
-      },
-      MM(date, locale) {
-        return locale.months[date.getMonth()];
-      },
-      y(date) {
-        return date.getFullYear();
-      },
-      yy(date) {
-        return padZero(date.getFullYear(), 2).slice(-2);
-      },
-      yyyy(date) {
-        return padZero(date.getFullYear(), 4);
-      },
-    };
-
-    // get month index in normal range (0 - 11) from any number
-    function normalizeMonth(monthIndex) {
-      return monthIndex > -1 ? monthIndex % 12 : normalizeMonth(monthIndex + 12);
-    }
-
-    function padZero(num, length) {
-      return num.toString().padStart(length, '0');
-    }
-
-    function parseFormatString(format) {
-      if (typeof format !== 'string') {
-        throw new Error("Invalid date format.");
       }
-      if (format in knownFormats) {
-        return knownFormats[format];
-      }
-
-      // sprit the format string into parts and seprators
-      const separators = format.split(reFormatTokens);
-      const parts = format.match(new RegExp(reFormatTokens, 'g'));
-      if (separators.length === 0 || !parts) {
-        throw new Error("Invalid date format.");
-      }
-
-      // collect format functions used in the format
-      const partFormatters = parts.map(token => formatFns[token]);
+      delete inOpts.language;
+      if (lang) {
+        language = config.language = lang;
 
-      // collect parse function keys used in the format
-      // iterate over parseFns' keys in order to keep the order of the keys.
-      const partParserKeys = Object.keys(parseFns).reduce((keys, key) => {
-        const token = parts.find(part => part[0] !== 'D' && part[0].toLowerCase() === key);
-        if (token) {
-          keys.push(key);
+        // update locale as well when updating language
+        const origLocale = locale || locales[defaultLang];
+        // use default language's properties for the fallback
+        locale = Object.assign({
+          format: defaultFormat,
+          weekStart: defaultWeekStart
+        }, locales[defaultLang]);
+        if (language !== defaultLang) {
+          Object.assign(locale, locales[language]);
+        }
+        config.locale = locale;
+        // if format and/or weekStart are the same as old locale's defaults,
+        // update them to new locale's defaults
+        if (format === origLocale.format) {
+          format = config.format = locale.format;
+        }
+        if (weekStart === origLocale.weekStart) {
+          weekStart = config.weekStart = locale.weekStart;
+          config.weekEnd = calcEndOfWeek(locale.weekStart);
         }
-        return keys;
-      }, []);
-
-      return knownFormats[format] = {
-        parser(dateStr, locale) {
-          const dateParts = dateStr.split(reNonDateParts).reduce((dtParts, part, index) => {
-            if (part.length > 0 && parts[index]) {
-              const token = parts[index][0];
-              if (token === 'M') {
-                dtParts.m = part;
-              } else if (token !== 'D') {
-                dtParts[token] = part;
-              }
-            }
-            return dtParts;
-          }, {});
-
-          // iterate over partParserkeys so that the parsing is made in the oder
-          // of year, month and day to prevent the day parser from correcting last
-          // day of month wrongly
-          return partParserKeys.reduce((origDate, key) => {
-            const newDate = parseFns[key](origDate, dateParts[key], locale);
-            // ingnore the part failed to parse
-            return isNaN(newDate) ? origDate : newDate;
-          }, today());
-        },
-        formatter(date, locale) {
-          let dateStr = partFormatters.reduce((str, fn, index) => {
-            return str += `${separators[index]}${fn(date, locale)}`;
-          }, '');
-          // separators' length is always parts' length + 1,
-          return dateStr += lastItemOf(separators);
-        },
-      };
-    }
-
-    function parseDate(dateStr, format, locale) {
-      if (dateStr instanceof Date || typeof dateStr === 'number') {
-        const date = stripTime(dateStr);
-        return isNaN(date) ? undefined : date;
-      }
-      if (!dateStr) {
-        return undefined;
-      }
-      if (dateStr === 'today') {
-        return today();
       }
+    }
 
-      if (format && format.toValue) {
-        const date = format.toValue(dateStr, format, locale);
-        return isNaN(date) ? undefined : stripTime(date);
+    if (inOpts.format) {
+      const hasToDisplay = typeof inOpts.format.toDisplay === 'function';
+      const hasToValue = typeof inOpts.format.toValue === 'function';
+      const validFormatString = reFormatTokens.test(inOpts.format);
+      if ((hasToDisplay && hasToValue) || validFormatString) {
+        format = config.format = inOpts.format;
       }
-
-      return parseFormatString(format).parser(dateStr, locale);
+      delete inOpts.format;
     }
 
-    function formatDate(date, format, locale) {
-      if (isNaN(date) || (!date && date !== 0)) {
-        return '';
+    //*** dates ***//
+    // while min and maxDate for "no limit" in the options are better to be null
+    // (especially when updating), the ones in the config have to be undefined
+    // because null is treated as 0 (= unix epoch) when comparing with time value
+    let minDt = minDate;
+    let maxDt = maxDate;
+    if (inOpts.minDate !== undefined) {
+      minDt = inOpts.minDate === null
+        ? dateValue(0, 0, 1)  // set 0000-01-01 to prevent negative values for year
+        : validateDate(inOpts.minDate, format, locale, minDt);
+      delete inOpts.minDate;
+    }
+    if (inOpts.maxDate !== undefined) {
+      maxDt = inOpts.maxDate === null
+        ? undefined
+        : validateDate(inOpts.maxDate, format, locale, maxDt);
+      delete inOpts.maxDate;
+    }
+    if (maxDt < minDt) {
+      minDate = config.minDate = maxDt;
+      maxDate = config.maxDate = minDt;
+    } else {
+      if (minDate !== minDt) {
+        minDate = config.minDate = minDt;
       }
-
-      const dateObj = typeof date === 'number' ? new Date(date) : date;
-
-      if (format.toDisplay) {
-        return format.toDisplay(dateObj, format, locale);
+      if (maxDate !== maxDt) {
+        maxDate = config.maxDate = maxDt;
       }
-
-      return parseFormatString(format).formatter(dateObj, locale);
     }
 
-    const listenerRegistry = new WeakMap();
-    const {addEventListener, removeEventListener} = EventTarget.prototype;
-
-    // Register event listeners to a key object
-    // listeners: array of listener definitions;
-    //   - each definition must be a flat array of event target and the arguments
-    //     used to call addEventListener() on the target
-    function registerListeners(keyObj, listeners) {
-      let registered = listenerRegistry.get(keyObj);
-      if (!registered) {
-        registered = [];
-        listenerRegistry.set(keyObj, registered);
+    if (inOpts.datesDisabled) {
+      config.datesDisabled = inOpts.datesDisabled.reduce((dates, dt) => {
+        const date = parseDate(dt, format, locale);
+        return date !== undefined ? pushUnique(dates, date) : dates;
+      }, []);
+      delete inOpts.datesDisabled;
+    }
+    if (inOpts.defaultViewDate !== undefined) {
+      const viewDate = parseDate(inOpts.defaultViewDate, format, locale);
+      if (viewDate !== undefined) {
+        config.defaultViewDate = viewDate;
       }
-      listeners.forEach((listener) => {
-        addEventListener.call(...listener);
-        registered.push(listener);
-      });
+      delete inOpts.defaultViewDate;
     }
 
-    function unregisterListeners(keyObj) {
-      let listeners = listenerRegistry.get(keyObj);
-      if (!listeners) {
-        return;
+    //*** days of week ***//
+    if (inOpts.weekStart !== undefined) {
+      const wkStart = Number(inOpts.weekStart) % 7;
+      if (!isNaN(wkStart)) {
+        weekStart = config.weekStart = wkStart;
+        config.weekEnd = calcEndOfWeek(wkStart);
       }
-      listeners.forEach((listener) => {
-        removeEventListener.call(...listener);
-      });
-      listenerRegistry.delete(keyObj);
+      delete inOpts.weekStart;
     }
-
-    // Event.composedPath() polyfill for Edge
-    // based on https://gist.github.com/kleinfreund/e9787d73776c0e3750dcfcdc89f100ec
-    if (!Event.prototype.composedPath) {
-      const getComposedPath = (node, path = []) => {
-        path.push(node);
-
-        let parent;
-        if (node.parentNode) {
-          parent = node.parentNode;
-        } else if (node.host) { // ShadowRoot
-          parent = node.host;
-        } else if (node.defaultView) {  // Document
-          parent = node.defaultView;
-        }
-        return parent ? getComposedPath(parent, path) : path;
-      };
-
-      Event.prototype.composedPath = function () {
-        return getComposedPath(this.target);
-      };
+    if (inOpts.daysOfWeekDisabled) {
+      config.daysOfWeekDisabled = inOpts.daysOfWeekDisabled.reduce(sanitizeDOW, []);
+      delete inOpts.daysOfWeekDisabled;
     }
-
-    function findFromPath(path, criteria, currentTarget, index = 0) {
-      const el = path[index];
-      if (criteria(el)) {
-        return el;
-      } else if (el === currentTarget || !el.parentElement) {
-        // stop when reaching currentTarget or <html>
-        return;
-      }
-      return findFromPath(path, criteria, currentTarget, index + 1);
-    }
-
-    // Search for the actual target of a delegated event
-    function findElementInEventPath(ev, selector) {
-      const criteria = typeof selector === 'function' ? selector : el => el.matches(selector);
-      return findFromPath(ev.composedPath(), criteria, ev.currentTarget);
-    }
-
-    // default locales
-    const locales = {
-      en: {
-        days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
-        daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
-        daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
-        months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
-        monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
-        today: "Today",
-        clear: "Clear",
-        titleFormat: "MM y"
-      }
-    };
-
-    // config options updatable by setOptions() and their default values
-    const defaultOptions = {
-      autohide: false,
-      beforeShowDay: null,
-      beforeShowDecade: null,
-      beforeShowMonth: null,
-      beforeShowYear: null,
-      calendarWeeks: false,
-      clearBtn: false,
-      dateDelimiter: ',',
-      datesDisabled: [],
-      daysOfWeekDisabled: [],
-      daysOfWeekHighlighted: [],
-      defaultViewDate: undefined, // placeholder, defaults to today() by the program
-      disableTouchKeyboard: false,
-      format: 'mm/dd/yyyy',
-      language: 'en',
-      maxDate: null,
-      maxNumberOfDates: 1,
-      maxView: 3,
-      minDate: null,
-      nextArrow: '»',
-      orientation: 'auto',
-      pickLevel: 0,
-      prevArrow: '«',
-      showDaysOfWeek: true,
-      showOnClick: true,
-      showOnFocus: true,
-      startView: 0,
-      title: '',
-      todayBtn: false,
-      todayBtnMode: 0,
-      todayHighlight: false,
-      updateOnBlur: true,
-      weekStart: 0,
-    };
-
-    const range = document.createRange();
-
-    function parseHTML(html) {
-      return range.createContextualFragment(html);
-    }
-
-    function hideElement(el) {
-      if (el.style.display === 'none') {
-        return;
-      }
-      // back up the existing display setting in data-style-display
-      if (el.style.display) {
-        el.dataset.styleDisplay = el.style.display;
-      }
-      el.style.display = 'none';
+    if (inOpts.daysOfWeekHighlighted) {
+      config.daysOfWeekHighlighted = inOpts.daysOfWeekHighlighted.reduce(sanitizeDOW, []);
+      delete inOpts.daysOfWeekHighlighted;
     }
 
-    function showElement(el) {
-      if (el.style.display !== 'none') {
-        return;
-      }
-      if (el.dataset.styleDisplay) {
-        // restore backed-up dispay property
-        el.style.display = el.dataset.styleDisplay;
-        delete el.dataset.styleDisplay;
-      } else {
-        el.style.display = '';
+    //*** multi date ***//
+    if (inOpts.maxNumberOfDates !== undefined) {
+      const maxNumberOfDates = parseInt(inOpts.maxNumberOfDates, 10);
+      if (maxNumberOfDates >= 0) {
+        config.maxNumberOfDates = maxNumberOfDates;
+        config.multidate = maxNumberOfDates !== 1;
       }
+      delete inOpts.maxNumberOfDates;
     }
-
-    function emptyChildNodes(el) {
-      if (el.firstChild) {
-        el.removeChild(el.firstChild);
-        emptyChildNodes(el);
-      }
+    if (inOpts.dateDelimiter) {
+      config.dateDelimiter = String(inOpts.dateDelimiter);
+      delete inOpts.dateDelimiter;
     }
 
-    function replaceChildNodes(el, newChildNodes) {
-      emptyChildNodes(el);
-      if (newChildNodes instanceof DocumentFragment) {
-        el.appendChild(newChildNodes);
-      } else if (typeof newChildNodes === 'string') {
-        el.appendChild(parseHTML(newChildNodes));
-      } else if (typeof newChildNodes.forEach === 'function') {
-        newChildNodes.forEach((node) => {
-          el.appendChild(node);
-        });
-      }
+    //*** pick level & view ***//
+    let newPickLevel = pickLevel;
+    if (inOpts.pickLevel !== undefined) {
+      newPickLevel = validateViewId(inOpts.pickLevel, 2);
+      delete inOpts.pickLevel;
     }
-
-    const {
-      language: defaultLang,
-      format: defaultFormat,
-      weekStart: defaultWeekStart,
-    } = defaultOptions;
-
-    // Reducer function to filter out invalid day-of-week from the input
-    function sanitizeDOW(dow, day) {
-      return dow.length < 6 && day >= 0 && day < 7
-        ? pushUnique(dow, day)
-        : dow;
+    if (newPickLevel !== pickLevel) {
+      pickLevel = config.pickLevel = newPickLevel;
     }
 
-    function calcEndOfWeek(startOfWeek) {
-      return (startOfWeek + 6) % 7;
+    let newMaxView = maxView;
+    if (inOpts.maxView !== undefined) {
+      newMaxView = validateViewId(inOpts.maxView, maxView);
+      delete inOpts.maxView;
     }
-
-    // validate input date. if invalid, fallback to the original value
-    function validateDate(value, format, locale, origValue) {
-      const date = parseDate(value, format, locale);
-      return date !== undefined ? date : origValue;
+    // ensure max view >= pick level
+    newMaxView = pickLevel > newMaxView ? pickLevel : newMaxView;
+    if (newMaxView !== maxView) {
+      maxView = config.maxView = newMaxView;
     }
 
-    // Validate viewId. if invalid, fallback to the original value
-    function validateViewId(value, origValue, max = 3) {
-      const viewId = parseInt(value, 10);
-      return viewId >= 0 && viewId <= max ? viewId : origValue;
+    let newStartView = startView;
+    if (inOpts.startView !== undefined) {
+      newStartView = validateViewId(inOpts.startView, newStartView);
+      delete inOpts.startView;
+    }
+    // ensure pick level <= start view <= max view
+    if (newStartView < pickLevel) {
+      newStartView = pickLevel;
+    } else if (newStartView > maxView) {
+      newStartView = maxView;
+    }
+    if (newStartView !== startView) {
+      config.startView = newStartView;
     }
 
-    // Create Datepicker configuration to set
-    function processOptions(options, datepicker) {
-      const inOpts = Object.assign({}, options);
-      const config = {};
-      const locales = datepicker.constructor.locales;
-      let {
-        format,
-        language,
-        locale,
-        maxDate,
-        maxView,
-        minDate,
-        pickLevel,
-        startView,
-        weekStart,
-      } = datepicker.config || {};
-
-      if (inOpts.language) {
-        let lang;
-        if (inOpts.language !== language) {
-          if (locales[inOpts.language]) {
-            lang = inOpts.language;
-          } else {
-            // Check if langauge + region tag can fallback to the one without
-            // region (e.g. fr-CA → fr)
-            lang = inOpts.language.split('-')[0];
-            if (locales[lang] === undefined) {
-              lang = false;
-            }
-          }
-        }
-        delete inOpts.language;
-        if (lang) {
-          language = config.language = lang;
-
-          // update locale as well when updating language
-          const origLocale = locale || locales[defaultLang];
-          // use default language's properties for the fallback
-          locale = Object.assign({
-            format: defaultFormat,
-            weekStart: defaultWeekStart
-          }, locales[defaultLang]);
-          if (language !== defaultLang) {
-            Object.assign(locale, locales[language]);
-          }
-          config.locale = locale;
-          // if format and/or weekStart are the same as old locale's defaults,
-          // update them to new locale's defaults
-          if (format === origLocale.format) {
-            format = config.format = locale.format;
-          }
-          if (weekStart === origLocale.weekStart) {
-            weekStart = config.weekStart = locale.weekStart;
-            config.weekEnd = calcEndOfWeek(locale.weekStart);
-          }
-        }
-      }
-
-      if (inOpts.format) {
-        const hasToDisplay = typeof inOpts.format.toDisplay === 'function';
-        const hasToValue = typeof inOpts.format.toValue === 'function';
-        const validFormatString = reFormatTokens.test(inOpts.format);
-        if ((hasToDisplay && hasToValue) || validFormatString) {
-          format = config.format = inOpts.format;
-        }
-        delete inOpts.format;
-      }
-
-      //*** dates ***//
-      // while min and maxDate for "no limit" in the options are better to be null
-      // (especially when updating), the ones in the config have to be undefined
-      // because null is treated as 0 (= unix epoch) when comparing with time value
-      let minDt = minDate;
-      let maxDt = maxDate;
-      if (inOpts.minDate !== undefined) {
-        minDt = inOpts.minDate === null
-          ? dateValue(0, 0, 1)  // set 0000-01-01 to prevent negative values for year
-          : validateDate(inOpts.minDate, format, locale, minDt);
-        delete inOpts.minDate;
-      }
-      if (inOpts.maxDate !== undefined) {
-        maxDt = inOpts.maxDate === null
-          ? undefined
-          : validateDate(inOpts.maxDate, format, locale, maxDt);
-        delete inOpts.maxDate;
-      }
-      if (maxDt < minDt) {
-        minDate = config.minDate = maxDt;
-        maxDate = config.maxDate = minDt;
-      } else {
-        if (minDate !== minDt) {
-          minDate = config.minDate = minDt;
-        }
-        if (maxDate !== maxDt) {
-          maxDate = config.maxDate = maxDt;
-        }
-      }
-
-      if (inOpts.datesDisabled) {
-        config.datesDisabled = inOpts.datesDisabled.reduce((dates, dt) => {
-          const date = parseDate(dt, format, locale);
-          return date !== undefined ? pushUnique(dates, date) : dates;
-        }, []);
-        delete inOpts.datesDisabled;
-      }
-      if (inOpts.defaultViewDate !== undefined) {
-        const viewDate = parseDate(inOpts.defaultViewDate, format, locale);
-        if (viewDate !== undefined) {
-          config.defaultViewDate = viewDate;
-        }
-        delete inOpts.defaultViewDate;
-      }
-
-      //*** days of week ***//
-      if (inOpts.weekStart !== undefined) {
-        const wkStart = Number(inOpts.weekStart) % 7;
-        if (!isNaN(wkStart)) {
-          weekStart = config.weekStart = wkStart;
-          config.weekEnd = calcEndOfWeek(wkStart);
-        }
-        delete inOpts.weekStart;
-      }
-      if (inOpts.daysOfWeekDisabled) {
-        config.daysOfWeekDisabled = inOpts.daysOfWeekDisabled.reduce(sanitizeDOW, []);
-        delete inOpts.daysOfWeekDisabled;
-      }
-      if (inOpts.daysOfWeekHighlighted) {
-        config.daysOfWeekHighlighted = inOpts.daysOfWeekHighlighted.reduce(sanitizeDOW, []);
-        delete inOpts.daysOfWeekHighlighted;
-      }
-
-      //*** multi date ***//
-      if (inOpts.maxNumberOfDates !== undefined) {
-        const maxNumberOfDates = parseInt(inOpts.maxNumberOfDates, 10);
-        if (maxNumberOfDates >= 0) {
-          config.maxNumberOfDates = maxNumberOfDates;
-          config.multidate = maxNumberOfDates !== 1;
-        }
-        delete inOpts.maxNumberOfDates;
-      }
-      if (inOpts.dateDelimiter) {
-        config.dateDelimiter = String(inOpts.dateDelimiter);
-        delete inOpts.dateDelimiter;
-      }
-
-      //*** pick level & view ***//
-      let newPickLevel = pickLevel;
-      if (inOpts.pickLevel !== undefined) {
-        newPickLevel = validateViewId(inOpts.pickLevel, 2);
-        delete inOpts.pickLevel;
-      }
-      if (newPickLevel !== pickLevel) {
-        pickLevel = config.pickLevel = newPickLevel;
-      }
-
-      let newMaxView = maxView;
-      if (inOpts.maxView !== undefined) {
-        newMaxView = validateViewId(inOpts.maxView, maxView);
-        delete inOpts.maxView;
-      }
-      // ensure max view >= pick level
-      newMaxView = pickLevel > newMaxView ? pickLevel : newMaxView;
-      if (newMaxView !== maxView) {
-        maxView = config.maxView = newMaxView;
-      }
-
-      let newStartView = startView;
-      if (inOpts.startView !== undefined) {
-        newStartView = validateViewId(inOpts.startView, newStartView);
-        delete inOpts.startView;
+    //*** template ***//
+    if (inOpts.prevArrow) {
+      const prevArrow = parseHTML(inOpts.prevArrow);
+      if (prevArrow.childNodes.length > 0) {
+        config.prevArrow = prevArrow.childNodes;
       }
-      // ensure pick level <= start view <= max view
-      if (newStartView < pickLevel) {
-        newStartView = pickLevel;
-      } else if (newStartView > maxView) {
-        newStartView = maxView;
-      }
-      if (newStartView !== startView) {
-        config.startView = newStartView;
+      delete inOpts.prevArrow;
+    }
+    if (inOpts.nextArrow) {
+      const nextArrow = parseHTML(inOpts.nextArrow);
+      if (nextArrow.childNodes.length > 0) {
+        config.nextArrow = nextArrow.childNodes;
       }
+      delete inOpts.nextArrow;
+    }
 
-      //*** template ***//
-      if (inOpts.prevArrow) {
-        const prevArrow = parseHTML(inOpts.prevArrow);
-        if (prevArrow.childNodes.length > 0) {
-          config.prevArrow = prevArrow.childNodes;
-        }
-        delete inOpts.prevArrow;
-      }
-      if (inOpts.nextArrow) {
-        const nextArrow = parseHTML(inOpts.nextArrow);
-        if (nextArrow.childNodes.length > 0) {
-          config.nextArrow = nextArrow.childNodes;
-        }
-        delete inOpts.nextArrow;
+    //*** misc ***//
+    if (inOpts.disableTouchKeyboard !== undefined) {
+      config.disableTouchKeyboard = 'ontouchstart' in document && !!inOpts.disableTouchKeyboard;
+      delete inOpts.disableTouchKeyboard;
+    }
+    if (inOpts.orientation) {
+      const orientation = inOpts.orientation.toLowerCase().split(/\s+/g);
+      config.orientation = {
+        x: orientation.find(x => (x === 'left' || x === 'right')) || 'auto',
+        y: orientation.find(y => (y === 'top' || y === 'bottom')) || 'auto',
+      };
+      delete inOpts.orientation;
+    }
+    if (inOpts.todayBtnMode !== undefined) {
+      switch(inOpts.todayBtnMode) {
+        case 0:
+        case 1:
+          config.todayBtnMode = inOpts.todayBtnMode;
       }
+      delete inOpts.todayBtnMode;
+    }
 
-      //*** misc ***//
-      if (inOpts.disableTouchKeyboard !== undefined) {
-        config.disableTouchKeyboard = 'ontouchstart' in document && !!inOpts.disableTouchKeyboard;
-        delete inOpts.disableTouchKeyboard;
-      }
-      if (inOpts.orientation) {
-        const orientation = inOpts.orientation.toLowerCase().split(/\s+/g);
-        config.orientation = {
-          x: orientation.find(x => (x === 'left' || x === 'right')) || 'auto',
-          y: orientation.find(y => (y === 'top' || y === 'bottom')) || 'auto',
-        };
-        delete inOpts.orientation;
+    //*** copy the rest ***//
+    Object.keys(inOpts).forEach((key) => {
+      if (inOpts[key] !== undefined && hasProperty(defaultOptions, key)) {
+        config[key] = inOpts[key];
       }
-      if (inOpts.todayBtnMode !== undefined) {
-        switch(inOpts.todayBtnMode) {
-          case 0:
-          case 1:
-            config.todayBtnMode = inOpts.todayBtnMode;
-        }
-        delete inOpts.todayBtnMode;
-      }
-
-      //*** copy the rest ***//
-      Object.keys(inOpts).forEach((key) => {
-        if (inOpts[key] !== undefined && hasProperty(defaultOptions, key)) {
-          config[key] = inOpts[key];
-        }
-      });
+    });
 
-      return config;
-    }
+    return config;
+  }
 
-    const pickerTemplate = optimizeTemplateHTML(`<div class="datepicker">
+  const pickerTemplate = optimizeTemplateHTML(`<div class="datepicker">
   <div class="datepicker-picker">
     <div class="datepicker-header">
       <div class="datepicker-title"></div>
@@ -1098,272 +1098,238 @@
   </div>
 </div>`);
 
-    const daysTemplate = optimizeTemplateHTML(`<div class="days">
+  const daysTemplate = optimizeTemplateHTML(`<div class="days">
   <div class="days-of-week">${createTagRepeat('span', 7, {class: 'dow'})}</div>
   <div class="datepicker-grid">${createTagRepeat('span', 42)}</div>
 </div>`);
 
-    const calendarWeeksTemplate = optimizeTemplateHTML(`<div class="calendar-weeks">
+  const calendarWeeksTemplate = optimizeTemplateHTML(`<div class="calendar-weeks">
   <div class="days-of-week"><span class="dow"></span></div>
   <div class="weeks">${createTagRepeat('span', 6, {class: 'week'})}</div>
 </div>`);
 
-    // Base class of the view classes
-    class View {
-      constructor(picker, config) {
-        Object.assign(this, config, {
-          picker,
-          element: parseHTML(`<div class="datepicker-view"></div>`).firstChild,
-          selected: [],
-        });
-        this.init(this.picker.datepicker.config);
+  // Base class of the view classes
+  class View {
+    constructor(picker, config) {
+      Object.assign(this, config, {
+        picker,
+        element: parseHTML(`<div class="datepicker-view"></div>`).firstChild,
+        selected: [],
+      });
+      this.init(this.picker.datepicker.config);
+    }
+
+    init(options) {
+      if (options.pickLevel !== undefined) {
+        this.isMinView = this.id === options.pickLevel;
       }
+      this.setOptions(options);
+      this.updateFocus();
+      this.updateSelection();
+    }
 
-      init(options) {
-        if (options.pickLevel !== undefined) {
-          this.isMinView = this.id === options.pickLevel;
-        }
-        this.setOptions(options);
-        this.updateFocus();
-        this.updateSelection();
+    // Execute beforeShow() callback and apply the result to the element
+    // args:
+    // - current - current value on the iteration on view rendering
+    // - timeValue - time value of the date to pass to beforeShow()
+    performBeforeHook(el, current, timeValue) {
+      let result = this.beforeShow(new Date(timeValue));
+      switch (typeof result) {
+        case 'boolean':
+          result = {enabled: result};
+          break;
+        case 'string':
+          result = {classes: result};
       }
 
-      // Execute beforeShow() callback and apply the result to the element
-      // args:
-      // - current - current value on the iteration on view rendering
-      // - timeValue - time value of the date to pass to beforeShow()
-      performBeforeHook(el, current, timeValue) {
-        let result = this.beforeShow(new Date(timeValue));
-        switch (typeof result) {
-          case 'boolean':
-            result = {enabled: result};
-            break;
-          case 'string':
-            result = {classes: result};
+      if (result) {
+        if (result.enabled === false) {
+          el.classList.add('disabled');
+          pushUnique(this.disabled, current);
         }
-
-        if (result) {
-          if (result.enabled === false) {
-            el.classList.add('disabled');
+        if (result.classes) {
+          const extraClasses = result.classes.split(/\s+/);
+          el.classList.add(...extraClasses);
+          if (extraClasses.includes('disabled')) {
             pushUnique(this.disabled, current);
           }
-          if (result.classes) {
-            const extraClasses = result.classes.split(/\s+/);
-            el.classList.add(...extraClasses);
-            if (extraClasses.includes('disabled')) {
-              pushUnique(this.disabled, current);
-            }
-          }
-          if (result.content) {
-            replaceChildNodes(el, result.content);
-          }
+        }
+        if (result.content) {
+          replaceChildNodes(el, result.content);
         }
       }
     }
+  }
 
-    class DaysView extends View {
-      constructor(picker) {
-        super(picker, {
-          id: 0,
-          name: 'days',
-          cellClass: 'day',
-        });
-      }
+  class DaysView extends View {
+    constructor(picker) {
+      super(picker, {
+        id: 0,
+        name: 'days',
+        cellClass: 'day',
+      });
+    }
 
-      init(options, onConstruction = true) {
-        if (onConstruction) {
-          const inner = parseHTML(daysTemplate).firstChild;
-          this.dow = inner.firstChild;
-          this.grid = inner.lastChild;
-          this.element.appendChild(inner);
-        }
-        super.init(options);
+    init(options, onConstruction = true) {
+      if (onConstruction) {
+        const inner = parseHTML(daysTemplate).firstChild;
+        this.dow = inner.firstChild;
+        this.grid = inner.lastChild;
+        this.element.appendChild(inner);
       }
+      super.init(options);
+    }
 
-      setOptions(options) {
-        let updateDOW;
+    setOptions(options) {
+      let updateDOW;
 
-        if (hasProperty(options, 'minDate')) {
-          this.minDate = options.minDate;
-        }
-        if (hasProperty(options, 'maxDate')) {
-          this.maxDate = options.maxDate;
-        }
-        if (options.datesDisabled) {
-          this.datesDisabled = options.datesDisabled;
-        }
-        if (options.daysOfWeekDisabled) {
-          this.daysOfWeekDisabled = options.daysOfWeekDisabled;
-          updateDOW = true;
-        }
-        if (options.daysOfWeekHighlighted) {
-          this.daysOfWeekHighlighted = options.daysOfWeekHighlighted;
-        }
-        if (options.todayHighlight !== undefined) {
-          this.todayHighlight = options.todayHighlight;
-        }
-        if (options.weekStart !== undefined) {
-          this.weekStart = options.weekStart;
-          this.weekEnd = options.weekEnd;
-          updateDOW = true;
-        }
-        if (options.locale) {
-          const locale = this.locale = options.locale;
-          this.dayNames = locale.daysMin;
-          this.switchLabelFormat = locale.titleFormat;
-          updateDOW = true;
-        }
-        if (options.beforeShowDay !== undefined) {
-          this.beforeShow = typeof options.beforeShowDay === 'function'
-            ? options.beforeShowDay
-            : undefined;
+      if (hasProperty(options, 'minDate')) {
+        this.minDate = options.minDate;
+      }
+      if (hasProperty(options, 'maxDate')) {
+        this.maxDate = options.maxDate;
+      }
+      if (options.datesDisabled) {
+        this.datesDisabled = options.datesDisabled;
+      }
+      if (options.daysOfWeekDisabled) {
+        this.daysOfWeekDisabled = options.daysOfWeekDisabled;
+        updateDOW = true;
+      }
+      if (options.daysOfWeekHighlighted) {
+        this.daysOfWeekHighlighted = options.daysOfWeekHighlighted;
+      }
+      if (options.todayHighlight !== undefined) {
+        this.todayHighlight = options.todayHighlight;
+      }
+      if (options.weekStart !== undefined) {
+        this.weekStart = options.weekStart;
+        this.weekEnd = options.weekEnd;
+        updateDOW = true;
+      }
+      if (options.locale) {
+        const locale = this.locale = options.locale;
+        this.dayNames = locale.daysMin;
+        this.switchLabelFormat = locale.titleFormat;
+        updateDOW = true;
+      }
+      if (options.beforeShowDay !== undefined) {
+        this.beforeShow = typeof options.beforeShowDay === 'function'
+          ? options.beforeShowDay
+          : undefined;
+      }
+
+      if (options.calendarWeeks !== undefined) {
+        if (options.calendarWeeks && !this.calendarWeeks) {
+          const weeksElem = parseHTML(calendarWeeksTemplate).firstChild;
+          this.calendarWeeks = {
+            element: weeksElem,
+            dow: weeksElem.firstChild,
+            weeks: weeksElem.lastChild,
+          };
+          this.element.insertBefore(weeksElem, this.element.firstChild);
+        } else if (this.calendarWeeks && !options.calendarWeeks) {
+          this.element.removeChild(this.calendarWeeks.element);
+          this.calendarWeeks = null;
         }
-
-        if (options.calendarWeeks !== undefined) {
-          if (options.calendarWeeks && !this.calendarWeeks) {
-            const weeksElem = parseHTML(calendarWeeksTemplate).firstChild;
-            this.calendarWeeks = {
-              element: weeksElem,
-              dow: weeksElem.firstChild,
-              weeks: weeksElem.lastChild,
-            };
-            this.element.insertBefore(weeksElem, this.element.firstChild);
-          } else if (this.calendarWeeks && !options.calendarWeeks) {
-            this.element.removeChild(this.calendarWeeks.element);
-            this.calendarWeeks = null;
+      }
+      if (options.showDaysOfWeek !== undefined) {
+        if (options.showDaysOfWeek) {
+          showElement(this.dow);
+          if (this.calendarWeeks) {
+            showElement(this.calendarWeeks.dow);
           }
-        }
-        if (options.showDaysOfWeek !== undefined) {
-          if (options.showDaysOfWeek) {
-            showElement(this.dow);
-            if (this.calendarWeeks) {
-              showElement(this.calendarWeeks.dow);
-            }
-          } else {
-            hideElement(this.dow);
-            if (this.calendarWeeks) {
-              hideElement(this.calendarWeeks.dow);
-            }
+        } else {
+          hideElement(this.dow);
+          if (this.calendarWeeks) {
+            hideElement(this.calendarWeeks.dow);
           }
         }
+      }
 
-        // update days-of-week when locale, daysOfweekDisabled or weekStart is changed
-        if (updateDOW) {
-          Array.from(this.dow.children).forEach((el, index) => {
-            const dow = (this.weekStart + index) % 7;
-            el.textContent = this.dayNames[dow];
-            el.className = this.daysOfWeekDisabled.includes(dow) ? 'dow disabled' : 'dow';
-          });
-        }
+      // update days-of-week when locale, daysOfweekDisabled or weekStart is changed
+      if (updateDOW) {
+        Array.from(this.dow.children).forEach((el, index) => {
+          const dow = (this.weekStart + index) % 7;
+          el.textContent = this.dayNames[dow];
+          el.className = this.daysOfWeekDisabled.includes(dow) ? 'dow disabled' : 'dow';
+        });
       }
+    }
 
-      // Apply update on the focused date to view's settings
-      updateFocus() {
-        const viewDate = new Date(this.picker.viewDate);
-        const viewYear = viewDate.getFullYear();
-        const viewMonth = viewDate.getMonth();
-        const firstOfMonth = dateValue(viewYear, viewMonth, 1);
-        const start = dayOfTheWeekOf(firstOfMonth, this.weekStart, this.weekStart);
+    // Apply update on the focused date to view's settings
+    updateFocus() {
+      const viewDate = new Date(this.picker.viewDate);
+      const viewYear = viewDate.getFullYear();
+      const viewMonth = viewDate.getMonth();
+      const firstOfMonth = dateValue(viewYear, viewMonth, 1);
+      const start = dayOfTheWeekOf(firstOfMonth, this.weekStart, this.weekStart);
 
-        this.first = firstOfMonth;
-        this.last = dateValue(viewYear, viewMonth + 1, 0);
-        this.start = start;
-        this.focused = this.picker.viewDate;
-      }
+      this.first = firstOfMonth;
+      this.last = dateValue(viewYear, viewMonth + 1, 0);
+      this.start = start;
+      this.focused = this.picker.viewDate;
+    }
 
-      // Apply update on the selected dates to view's settings
-      updateSelection() {
-        const {dates, rangepicker} = this.picker.datepicker;
-        this.selected = dates;
-        if (rangepicker) {
-          this.range = rangepicker.dates;
-        }
+    // Apply update on the selected dates to view's settings
+    updateSelection() {
+      const {dates, rangepicker} = this.picker.datepicker;
+      this.selected = dates;
+      if (rangepicker) {
+        this.range = rangepicker.dates;
       }
+    }
 
-       // Update the entire view UI
-      render() {
-        // update today marker on ever render
-        this.today = this.todayHighlight ? today() : undefined;
-        // refresh disabled dates on every render in order to clear the ones added
-        // by beforeShow hook at previous render
-        this.disabled = [...this.datesDisabled];
-
-        const switchLabel = formatDate(this.focused, this.switchLabelFormat, this.locale);
-        this.picker.setViewSwitchLabel(switchLabel);
-        this.picker.setPrevBtnDisabled(this.first <= this.minDate);
-        this.picker.setNextBtnDisabled(this.last >= this.maxDate);
-
-        if (this.calendarWeeks) {
-          // start of the UTC week (Monday) of the 1st of the month
-          const startOfWeek = dayOfTheWeekOf(this.first, 1, 1);
-          Array.from(this.calendarWeeks.weeks.children).forEach((el, index) => {
-            el.textContent = getWeek(addWeeks(startOfWeek, index));
-          });
-        }
-        Array.from(this.grid.children).forEach((el, index) => {
-          const classList = el.classList;
-          const current = addDays(this.start, index);
-          const date = new Date(current);
-          const day = date.getDay();
-
-          el.className = `datepicker-cell ${this.cellClass}`;
-          el.dataset.date = current;
-          el.textContent = date.getDate();
+     // Update the entire view UI
+    render() {
+      // update today marker on ever render
+      this.today = this.todayHighlight ? today() : undefined;
+      // refresh disabled dates on every render in order to clear the ones added
+      // by beforeShow hook at previous render
+      this.disabled = [...this.datesDisabled];
 
-          if (current < this.first) {
-            classList.add('prev');
-          } else if (current > this.last) {
-            classList.add('next');
-          }
-          if (this.today === current) {
-            classList.add('today');
-          }
-          if (current < this.minDate || current > this.maxDate || this.disabled.includes(current)) {
-            classList.add('disabled');
-          }
-          if (this.daysOfWeekDisabled.includes(day)) {
-            classList.add('disabled');
-            pushUnique(this.disabled, current);
-          }
-          if (this.daysOfWeekHighlighted.includes(day)) {
-            classList.add('highlighted');
-          }
-          if (this.range) {
-            const [rangeStart, rangeEnd] = this.range;
-            if (current > rangeStart && current < rangeEnd) {
-              classList.add('range');
-            }
-            if (current === rangeStart) {
-              classList.add('range-start');
-            }
-            if (current === rangeEnd) {
-              classList.add('range-end');
-            }
-          }
-          if (this.selected.includes(current)) {
-            classList.add('selected');
-          }
-          if (current === this.focused) {
-            classList.add('focused');
-          }
+      const switchLabel = formatDate(this.focused, this.switchLabelFormat, this.locale);
+      this.picker.setViewSwitchLabel(switchLabel);
+      this.picker.setPrevBtnDisabled(this.first <= this.minDate);
+      this.picker.setNextBtnDisabled(this.last >= this.maxDate);
 
-          if (this.beforeShow) {
-            this.performBeforeHook(el, current, current);
-          }
+      if (this.calendarWeeks) {
+        // start of the UTC week (Monday) of the 1st of the month
+        const startOfWeek = dayOfTheWeekOf(this.first, 1, 1);
+        Array.from(this.calendarWeeks.weeks.children).forEach((el, index) => {
+          el.textContent = getWeek(addWeeks(startOfWeek, index));
         });
       }
+      Array.from(this.grid.children).forEach((el, index) => {
+        const classList = el.classList;
+        const current = addDays(this.start, index);
+        const date = new Date(current);
+        const day = date.getDay();
 
-      // Update the view UI by applying the changes of selected and focused items
-      refresh() {
-        const [rangeStart, rangeEnd] = this.range || [];
-        this.grid
-          .querySelectorAll('.range, .range-start, .range-end, .selected, .focused')
-          .forEach((el) => {
-            el.classList.remove('range', 'range-start', 'range-end', 'selected', 'focused');
-          });
-        Array.from(this.grid.children).forEach((el) => {
-          const current = Number(el.dataset.date);
-          const classList = el.classList;
+        el.className = `datepicker-cell ${this.cellClass}`;
+        el.dataset.date = current;
+        el.textContent = date.getDate();
+
+        if (current < this.first) {
+          classList.add('prev');
+        } else if (current > this.last) {
+          classList.add('next');
+        }
+        if (this.today === current) {
+          classList.add('today');
+        }
+        if (current < this.minDate || current > this.maxDate || this.disabled.includes(current)) {
+          classList.add('disabled');
+        }
+        if (this.daysOfWeekDisabled.includes(day)) {
+          classList.add('disabled');
+          pushUnique(this.disabled, current);
+        }
+        if (this.daysOfWeekHighlighted.includes(day)) {
+          classList.add('highlighted');
+        }
+        if (this.range) {
+          const [rangeStart, rangeEnd] = this.range;
           if (current > rangeStart && current < rangeEnd) {
             classList.add('range');
           }
@@ -1373,189 +1339,189 @@
           if (current === rangeEnd) {
             classList.add('range-end');
           }
-          if (this.selected.includes(current)) {
-            classList.add('selected');
-          }
-          if (current === this.focused) {
-            classList.add('focused');
-          }
-        });
-      }
+        }
+        if (this.selected.includes(current)) {
+          classList.add('selected');
+        }
+        if (current === this.focused) {
+          classList.add('focused');
+        }
+
+        if (this.beforeShow) {
+          this.performBeforeHook(el, current, current);
+        }
+      });
+    }
 
-      // Update the view UI by applying the change of focused item
-      refreshFocus() {
-        const index = Math.round((this.focused - this.start) / 86400000);
-        this.grid.querySelectorAll('.focused').forEach((el) => {
-          el.classList.remove('focused');
+    // Update the view UI by applying the changes of selected and focused items
+    refresh() {
+      const [rangeStart, rangeEnd] = this.range || [];
+      this.grid
+        .querySelectorAll('.range, .range-start, .range-end, .selected, .focused')
+        .forEach((el) => {
+          el.classList.remove('range', 'range-start', 'range-end', 'selected', 'focused');
         });
-        this.grid.children[index].classList.add('focused');
-      }
+      Array.from(this.grid.children).forEach((el) => {
+        const current = Number(el.dataset.date);
+        const classList = el.classList;
+        if (current > rangeStart && current < rangeEnd) {
+          classList.add('range');
+        }
+        if (current === rangeStart) {
+          classList.add('range-start');
+        }
+        if (current === rangeEnd) {
+          classList.add('range-end');
+        }
+        if (this.selected.includes(current)) {
+          classList.add('selected');
+        }
+        if (current === this.focused) {
+          classList.add('focused');
+        }
+      });
     }
 
-    function computeMonthRange(range, thisYear) {
-      if (!range || !range[0] || !range[1]) {
-        return;
-      }
+    // Update the view UI by applying the change of focused item
+    refreshFocus() {
+      const index = Math.round((this.focused - this.start) / 86400000);
+      this.grid.querySelectorAll('.focused').forEach((el) => {
+        el.classList.remove('focused');
+      });
+      this.grid.children[index].classList.add('focused');
+    }
+  }
 
-      const [[startY, startM], [endY, endM]] = range;
-      if (startY > thisYear || endY < thisYear) {
-        return;
-      }
-      return [
-        startY === thisYear ? startM : -1,
-        endY === thisYear ? endM : 12,
-      ];
+  function computeMonthRange(range, thisYear) {
+    if (!range || !range[0] || !range[1]) {
+      return;
     }
 
-    class MonthsView extends View {
-      constructor(picker) {
-        super(picker, {
-          id: 1,
-          name: 'months',
-          cellClass: 'month',
-        });
-      }
+    const [[startY, startM], [endY, endM]] = range;
+    if (startY > thisYear || endY < thisYear) {
+      return;
+    }
+    return [
+      startY === thisYear ? startM : -1,
+      endY === thisYear ? endM : 12,
+    ];
+  }
 
-      init(options, onConstruction = true) {
-        if (onConstruction) {
-          this.grid = this.element;
-          this.element.classList.add('months', 'datepicker-grid');
-          this.grid.appendChild(parseHTML(createTagRepeat('span', 12, {'data-month': ix => ix})));
-        }
-        super.init(options);
+  class MonthsView extends View {
+    constructor(picker) {
+      super(picker, {
+        id: 1,
+        name: 'months',
+        cellClass: 'month',
+      });
+    }
+
+    init(options, onConstruction = true) {
+      if (onConstruction) {
+        this.grid = this.element;
+        this.element.classList.add('months', 'datepicker-grid');
+        this.grid.appendChild(parseHTML(createTagRepeat('span', 12, {'data-month': ix => ix})));
       }
+      super.init(options);
+    }
 
-      setOptions(options) {
-        if (options.locale) {
-          this.monthNames = options.locale.monthsShort;
-        }
-        if (hasProperty(options, 'minDate')) {
-          if (options.minDate === undefined) {
-            this.minYear = this.minMonth = this.minDate = undefined;
-          } else {
-            const minDateObj = new Date(options.minDate);
-            this.minYear = minDateObj.getFullYear();
-            this.minMonth = minDateObj.getMonth();
-            this.minDate = minDateObj.setDate(1);
-          }
-        }
-        if (hasProperty(options, 'maxDate')) {
-          if (options.maxDate === undefined) {
-            this.maxYear = this.maxMonth = this.maxDate = undefined;
-          } else {
-            const maxDateObj = new Date(options.maxDate);
-            this.maxYear = maxDateObj.getFullYear();
-            this.maxMonth = maxDateObj.getMonth();
-            this.maxDate = dateValue(this.maxYear, this.maxMonth + 1, 0);
-          }
+    setOptions(options) {
+      if (options.locale) {
+        this.monthNames = options.locale.monthsShort;
+      }
+      if (hasProperty(options, 'minDate')) {
+        if (options.minDate === undefined) {
+          this.minYear = this.minMonth = this.minDate = undefined;
+        } else {
+          const minDateObj = new Date(options.minDate);
+          this.minYear = minDateObj.getFullYear();
+          this.minMonth = minDateObj.getMonth();
+          this.minDate = minDateObj.setDate(1);
         }
-        if (options.beforeShowMonth !== undefined) {
-          this.beforeShow = typeof options.beforeShowMonth === 'function'
-            ? options.beforeShowMonth
-            : undefined;
+      }
+      if (hasProperty(options, 'maxDate')) {
+        if (options.maxDate === undefined) {
+          this.maxYear = this.maxMonth = this.maxDate = undefined;
+        } else {
+          const maxDateObj = new Date(options.maxDate);
+          this.maxYear = maxDateObj.getFullYear();
+          this.maxMonth = maxDateObj.getMonth();
+          this.maxDate = dateValue(this.maxYear, this.maxMonth + 1, 0);
         }
       }
-
-      // Update view's settings to reflect the viewDate set on the picker
-      updateFocus() {
-        const viewDate = new Date(this.picker.viewDate);
-        this.year = viewDate.getFullYear();
-        this.focused = viewDate.getMonth();
+      if (options.beforeShowMonth !== undefined) {
+        this.beforeShow = typeof options.beforeShowMonth === 'function'
+          ? options.beforeShowMonth
+          : undefined;
       }
+    }
 
-      // Update view's settings to reflect the selected dates
-      updateSelection() {
-        const {dates, rangepicker} = this.picker.datepicker;
-        this.selected = dates.reduce((selected, timeValue) => {
-          const date = new Date(timeValue);
-          const year = date.getFullYear();
-          const month = date.getMonth();
-          if (selected[year] === undefined) {
-            selected[year] = [month];
-          } else {
-            pushUnique(selected[year], month);
-          }
-          return selected;
-        }, {});
-        if (rangepicker && rangepicker.dates) {
-          this.range = rangepicker.dates.map(timeValue => {
-            const date = new Date(timeValue);
-            return isNaN(date) ? undefined : [date.getFullYear(), date.getMonth()];
-          });
+    // Update view's settings to reflect the viewDate set on the picker
+    updateFocus() {
+      const viewDate = new Date(this.picker.viewDate);
+      this.year = viewDate.getFullYear();
+      this.focused = viewDate.getMonth();
+    }
+
+    // Update view's settings to reflect the selected dates
+    updateSelection() {
+      const {dates, rangepicker} = this.picker.datepicker;
+      this.selected = dates.reduce((selected, timeValue) => {
+        const date = new Date(timeValue);
+        const year = date.getFullYear();
+        const month = date.getMonth();
+        if (selected[year] === undefined) {
+          selected[year] = [month];
+        } else {
+          pushUnique(selected[year], month);
         }
+        return selected;
+      }, {});
+      if (rangepicker && rangepicker.dates) {
+        this.range = rangepicker.dates.map(timeValue => {
+          const date = new Date(timeValue);
+          return isNaN(date) ? undefined : [date.getFullYear(), date.getMonth()];
+        });
       }
+    }
 
-      // Update the entire view UI
-      render() {
-        // refresh disabled months on every render in order to clear the ones added
-        // by beforeShow hook at previous render
-        this.disabled = [];
-
-        this.picker.setViewSwitchLabel(this.year);
-        this.picker.setPrevBtnDisabled(this.year <= this.minYear);
-        this.picker.setNextBtnDisabled(this.year >= this.maxYear);
-
-        const selected = this.selected[this.year] || [];
-        const yrOutOfRange = this.year < this.minYear || this.year > this.maxYear;
-        const isMinYear = this.year === this.minYear;
-        const isMaxYear = this.year === this.maxYear;
-        const range = computeMonthRange(this.range, this.year);
-
-        Array.from(this.grid.children).forEach((el, index) => {
-          const classList = el.classList;
-          const date = dateValue(this.year, index, 1);
-
-          el.className = `datepicker-cell ${this.cellClass}`;
-          if (this.isMinView) {
-            el.dataset.date = date;
-          }
-          // reset text on every render to clear the custom content set
-          // by beforeShow hook at previous render
-          el.textContent = this.monthNames[index];
-
-          if (
-            yrOutOfRange
-            || isMinYear && index < this.minMonth
-            || isMaxYear && index > this.maxMonth
-          ) {
-            classList.add('disabled');
-          }
-          if (range) {
-            const [rangeStart, rangeEnd] = range;
-            if (index > rangeStart && index < rangeEnd) {
-              classList.add('range');
-            }
-            if (index === rangeStart) {
-              classList.add('range-start');
-            }
-            if (index === rangeEnd) {
-              classList.add('range-end');
-            }
-          }
-          if (selected.includes(index)) {
-            classList.add('selected');
-          }
-          if (index === this.focused) {
-            classList.add('focused');
-          }
+    // Update the entire view UI
+    render() {
+      // refresh disabled months on every render in order to clear the ones added
+      // by beforeShow hook at previous render
+      this.disabled = [];
 
-          if (this.beforeShow) {
-            this.performBeforeHook(el, index, date);
-          }
-        });
-      }
+      this.picker.setViewSwitchLabel(this.year);
+      this.picker.setPrevBtnDisabled(this.year <= this.minYear);
+      this.picker.setNextBtnDisabled(this.year >= this.maxYear);
 
-      // Update the view UI by applying the changes of selected and focused items
-      refresh() {
-        const selected = this.selected[this.year] || [];
-        const [rangeStart, rangeEnd] = computeMonthRange(this.range, this.year) || [];
-        this.grid
-          .querySelectorAll('.range, .range-start, .range-end, .selected, .focused')
-          .forEach((el) => {
-            el.classList.remove('range', 'range-start', 'range-end', 'selected', 'focused');
-          });
-        Array.from(this.grid.children).forEach((el, index) => {
-          const classList = el.classList;
+      const selected = this.selected[this.year] || [];
+      const yrOutOfRange = this.year < this.minYear || this.year > this.maxYear;
+      const isMinYear = this.year === this.minYear;
+      const isMaxYear = this.year === this.maxYear;
+      const range = computeMonthRange(this.range, this.year);
+
+      Array.from(this.grid.children).forEach((el, index) => {
+        const classList = el.classList;
+        const date = dateValue(this.year, index, 1);
+
+        el.className = `datepicker-cell ${this.cellClass}`;
+        if (this.isMinView) {
+          el.dataset.date = date;
+        }
+        // reset text on every render to clear the custom content set
+        // by beforeShow hook at previous render
+        el.textContent = this.monthNames[index];
+
+        if (
+          yrOutOfRange
+          || isMinYear && index < this.minMonth
+          || isMaxYear && index > this.maxMonth
+        ) {
+          classList.add('disabled');
+        }
+        if (range) {
+          const [rangeStart, rangeEnd] = range;
           if (index > rangeStart && index < rangeEnd) {
             classList.add('range');
           }
@@ -1565,160 +1531,160 @@
           if (index === rangeEnd) {
             classList.add('range-end');
           }
-          if (selected.includes(index)) {
-            classList.add('selected');
-          }
-          if (index === this.focused) {
-            classList.add('focused');
-          }
-        });
-      }
+        }
+        if (selected.includes(index)) {
+          classList.add('selected');
+        }
+        if (index === this.focused) {
+          classList.add('focused');
+        }
+
+        if (this.beforeShow) {
+          this.performBeforeHook(el, index, date);
+        }
+      });
+    }
 
-      // Update the view UI by applying the change of focused item
-      refreshFocus() {
-        this.grid.querySelectorAll('.focused').forEach((el) => {
-          el.classList.remove('focused');
+    // Update the view UI by applying the changes of selected and focused items
+    refresh() {
+      const selected = this.selected[this.year] || [];
+      const [rangeStart, rangeEnd] = computeMonthRange(this.range, this.year) || [];
+      this.grid
+        .querySelectorAll('.range, .range-start, .range-end, .selected, .focused')
+        .forEach((el) => {
+          el.classList.remove('range', 'range-start', 'range-end', 'selected', 'focused');
         });
-        this.grid.children[this.focused].classList.add('focused');
-      }
+      Array.from(this.grid.children).forEach((el, index) => {
+        const classList = el.classList;
+        if (index > rangeStart && index < rangeEnd) {
+          classList.add('range');
+        }
+        if (index === rangeStart) {
+          classList.add('range-start');
+        }
+        if (index === rangeEnd) {
+          classList.add('range-end');
+        }
+        if (selected.includes(index)) {
+          classList.add('selected');
+        }
+        if (index === this.focused) {
+          classList.add('focused');
+        }
+      });
+    }
+
+    // Update the view UI by applying the change of focused item
+    refreshFocus() {
+      this.grid.querySelectorAll('.focused').forEach((el) => {
+        el.classList.remove('focused');
+      });
+      this.grid.children[this.focused].classList.add('focused');
     }
+  }
 
-    function toTitleCase(word) {
-      return [...word].reduce((str, ch, ix) => str += ix ? ch : ch.toUpperCase(), '');
+  function toTitleCase(word) {
+    return [...word].reduce((str, ch, ix) => str += ix ? ch : ch.toUpperCase(), '');
+  }
+
+  // Class representing the years and decades view elements
+  class YearsView extends View {
+    constructor(picker, config) {
+      super(picker, config);
     }
 
-    // Class representing the years and decades view elements
-    class YearsView extends View {
-      constructor(picker, config) {
-        super(picker, config);
+    init(options, onConstruction = true) {
+      if (onConstruction) {
+        this.navStep = this.step * 10;
+        this.beforeShowOption = `beforeShow${toTitleCase(this.cellClass)}`;
+        this.grid = this.element;
+        this.element.classList.add(this.name, 'datepicker-grid');
+        this.grid.appendChild(parseHTML(createTagRepeat('span', 12)));
       }
+      super.init(options);
+    }
 
-      init(options, onConstruction = true) {
-        if (onConstruction) {
-          this.navStep = this.step * 10;
-          this.beforeShowOption = `beforeShow${toTitleCase(this.cellClass)}`;
-          this.grid = this.element;
-          this.element.classList.add(this.name, 'datepicker-grid');
-          this.grid.appendChild(parseHTML(createTagRepeat('span', 12)));
+    setOptions(options) {
+      if (hasProperty(options, 'minDate')) {
+        if (options.minDate === undefined) {
+          this.minYear = this.minDate = undefined;
+        } else {
+          this.minYear = startOfYearPeriod(options.minDate, this.step);
+          this.minDate = dateValue(this.minYear, 0, 1);
         }
-        super.init(options);
       }
-
-      setOptions(options) {
-        if (hasProperty(options, 'minDate')) {
-          if (options.minDate === undefined) {
-            this.minYear = this.minDate = undefined;
-          } else {
-            this.minYear = startOfYearPeriod(options.minDate, this.step);
-            this.minDate = dateValue(this.minYear, 0, 1);
-          }
-        }
-        if (hasProperty(options, 'maxDate')) {
-          if (options.maxDate === undefined) {
-            this.maxYear = this.maxDate = undefined;
-          } else {
-            this.maxYear = startOfYearPeriod(options.maxDate, this.step);
-            this.maxDate = dateValue(this.maxYear, 11, 31);
-          }
-        }
-        if (options[this.beforeShowOption] !== undefined) {
-          const beforeShow = options[this.beforeShowOption];
-          this.beforeShow = typeof beforeShow === 'function' ? beforeShow : undefined;
+      if (hasProperty(options, 'maxDate')) {
+        if (options.maxDate === undefined) {
+          this.maxYear = this.maxDate = undefined;
+        } else {
+          this.maxYear = startOfYearPeriod(options.maxDate, this.step);
+          this.maxDate = dateValue(this.maxYear, 11, 31);
         }
       }
-
-      // Update view's settings to reflect the viewDate set on the picker
-      updateFocus() {
-        const viewDate = new Date(this.picker.viewDate);
-        const first = startOfYearPeriod(viewDate, this.navStep);
-        const last = first + 9 * this.step;
-
-        this.first = first;
-        this.last = last;
-        this.start = first - this.step;
-        this.focused = startOfYearPeriod(viewDate, this.step);
+      if (options[this.beforeShowOption] !== undefined) {
+        const beforeShow = options[this.beforeShowOption];
+        this.beforeShow = typeof beforeShow === 'function' ? beforeShow : undefined;
       }
+    }
 
-      // Update view's settings to reflect the selected dates
-      updateSelection() {
-        const {dates, rangepicker} = this.picker.datepicker;
-        this.selected = dates.reduce((years, timeValue) => {
-          return pushUnique(years, startOfYearPeriod(timeValue, this.step));
-        }, []);
-        if (rangepicker && rangepicker.dates) {
-          this.range = rangepicker.dates.map(timeValue => {
-            if (timeValue !== undefined) {
-              return startOfYearPeriod(timeValue, this.step);
-            }
-          });
-        }
-      }
+    // Update view's settings to reflect the viewDate set on the picker
+    updateFocus() {
+      const viewDate = new Date(this.picker.viewDate);
+      const first = startOfYearPeriod(viewDate, this.navStep);
+      const last = first + 9 * this.step;
 
-      // Update the entire view UI
-      render() {
-        // refresh disabled years on every render in order to clear the ones added
-        // by beforeShow hook at previous render
-        this.disabled = [];
+      this.first = first;
+      this.last = last;
+      this.start = first - this.step;
+      this.focused = startOfYearPeriod(viewDate, this.step);
+    }
 
-        this.picker.setViewSwitchLabel(`${this.first}-${this.last}`);
-        this.picker.setPrevBtnDisabled(this.first <= this.minYear);
-        this.picker.setNextBtnDisabled(this.last >= this.maxYear);
+    // Update view's settings to reflect the selected dates
+    updateSelection() {
+      const {dates, rangepicker} = this.picker.datepicker;
+      this.selected = dates.reduce((years, timeValue) => {
+        return pushUnique(years, startOfYearPeriod(timeValue, this.step));
+      }, []);
+      if (rangepicker && rangepicker.dates) {
+        this.range = rangepicker.dates.map(timeValue => {
+          if (timeValue !== undefined) {
+            return startOfYearPeriod(timeValue, this.step);
+          }
+        });
+      }
+    }
 
-        Array.from(this.grid.children).forEach((el, index) => {
-          const classList = el.classList;
-          const current = this.start + (index * this.step);
-          const date = dateValue(current, 0, 1);
+    // Update the entire view UI
+    render() {
+      // refresh disabled years on every render in order to clear the ones added
+      // by beforeShow hook at previous render
+      this.disabled = [];
 
-          el.className = `datepicker-cell ${this.cellClass}`;
-          if (this.isMinView) {
-            el.dataset.date = date;
-          }
-          el.textContent = el.dataset.year = current;
+      this.picker.setViewSwitchLabel(`${this.first}-${this.last}`);
+      this.picker.setPrevBtnDisabled(this.first <= this.minYear);
+      this.picker.setNextBtnDisabled(this.last >= this.maxYear);
 
-          if (index === 0) {
-            classList.add('prev');
-          } else if (index === 11) {
-            classList.add('next');
-          }
-          if (current < this.minYear || current > this.maxYear) {
-            classList.add('disabled');
-          }
-          if (this.range) {
-            const [rangeStart, rangeEnd] = this.range;
-            if (current > rangeStart && current < rangeEnd) {
-              classList.add('range');
-            }
-            if (current === rangeStart) {
-              classList.add('range-start');
-            }
-            if (current === rangeEnd) {
-              classList.add('range-end');
-            }
-          }
-          if (this.selected.includes(current)) {
-            classList.add('selected');
-          }
-          if (current === this.focused) {
-            classList.add('focused');
-          }
+      Array.from(this.grid.children).forEach((el, index) => {
+        const classList = el.classList;
+        const current = this.start + (index * this.step);
+        const date = dateValue(current, 0, 1);
 
-          if (this.beforeShow) {
-            this.performBeforeHook(el, current, date);
-          }
-        });
-      }
+        el.className = `datepicker-cell ${this.cellClass}`;
+        if (this.isMinView) {
+          el.dataset.date = date;
+        }
+        el.textContent = el.dataset.year = current;
 
-      // Update the view UI by applying the changes of selected and focused items
-      refresh() {
-        const [rangeStart, rangeEnd] = this.range || [];
-        this.grid
-          .querySelectorAll('.range, .range-start, .range-end, .selected, .focused')
-          .forEach((el) => {
-            el.classList.remove('range', 'range-start', 'range-end', 'selected', 'focused');
-          });
-        Array.from(this.grid.children).forEach((el) => {
-          const current = Number(el.textContent);
-          const classList = el.classList;
+        if (index === 0) {
+          classList.add('prev');
+        } else if (index === 11) {
+          classList.add('next');
+        }
+        if (current < this.minYear || current > this.maxYear) {
+          classList.add('disabled');
+        }
+        if (this.range) {
+          const [rangeStart, rangeEnd] = this.range;
           if (current > rangeStart && current < rangeEnd) {
             classList.add('range');
           }
@@ -1728,12021 +1694,12055 @@
           if (current === rangeEnd) {
             classList.add('range-end');
           }
-          if (this.selected.includes(current)) {
-            classList.add('selected');
-          }
-          if (current === this.focused) {
-            classList.add('focused');
-          }
-        });
-      }
+        }
+        if (this.selected.includes(current)) {
+          classList.add('selected');
+        }
+        if (current === this.focused) {
+          classList.add('focused');
+        }
 
-      // Update the view UI by applying the change of focused item
-      refreshFocus() {
-        const index = Math.round((this.focused - this.start) / this.step);
-        this.grid.querySelectorAll('.focused').forEach((el) => {
-          el.classList.remove('focused');
-        });
-        this.grid.children[index].classList.add('focused');
-      }
+        if (this.beforeShow) {
+          this.performBeforeHook(el, current, date);
+        }
+      });
     }
 
-    function triggerDatepickerEvent(datepicker, type) {
-      const detail = {
-        date: datepicker.getDate(),
-        viewDate: new Date(datepicker.picker.viewDate),
-        viewId: datepicker.picker.currentView.id,
-        datepicker,
-      };
-      datepicker.element.dispatchEvent(new CustomEvent(type, {detail}));
+    // Update the view UI by applying the changes of selected and focused items
+    refresh() {
+      const [rangeStart, rangeEnd] = this.range || [];
+      this.grid
+        .querySelectorAll('.range, .range-start, .range-end, .selected, .focused')
+        .forEach((el) => {
+          el.classList.remove('range', 'range-start', 'range-end', 'selected', 'focused');
+        });
+      Array.from(this.grid.children).forEach((el) => {
+        const current = Number(el.textContent);
+        const classList = el.classList;
+        if (current > rangeStart && current < rangeEnd) {
+          classList.add('range');
+        }
+        if (current === rangeStart) {
+          classList.add('range-start');
+        }
+        if (current === rangeEnd) {
+          classList.add('range-end');
+        }
+        if (this.selected.includes(current)) {
+          classList.add('selected');
+        }
+        if (current === this.focused) {
+          classList.add('focused');
+        }
+      });
     }
 
-    // direction: -1 (to previous), 1 (to next)
-    function goToPrevOrNext(datepicker, direction) {
-      const {minDate, maxDate} = datepicker.config;
-      const {currentView, viewDate} = datepicker.picker;
-      let newViewDate;
-      switch (currentView.id) {
-        case 0:
-          newViewDate = addMonths(viewDate, direction);
-          break;
-        case 1:
-          newViewDate = addYears(viewDate, direction);
-          break;
-        default:
-          newViewDate = addYears(viewDate, direction * currentView.navStep);
-      }
-      newViewDate = limitToRange(newViewDate, minDate, maxDate);
-      datepicker.picker.changeFocus(newViewDate).render();
+    // Update the view UI by applying the change of focused item
+    refreshFocus() {
+      const index = Math.round((this.focused - this.start) / this.step);
+      this.grid.querySelectorAll('.focused').forEach((el) => {
+        el.classList.remove('focused');
+      });
+      this.grid.children[index].classList.add('focused');
     }
+  }
 
-    function switchView(datepicker) {
-      const viewId = datepicker.picker.currentView.id;
-      if (viewId === datepicker.config.maxView) {
+  function triggerDatepickerEvent(datepicker, type) {
+    const detail = {
+      date: datepicker.getDate(),
+      viewDate: new Date(datepicker.picker.viewDate),
+      viewId: datepicker.picker.currentView.id,
+      datepicker,
+    };
+    datepicker.element.dispatchEvent(new CustomEvent(type, {detail}));
+  }
+
+  // direction: -1 (to previous), 1 (to next)
+  function goToPrevOrNext(datepicker, direction) {
+    const {minDate, maxDate} = datepicker.config;
+    const {currentView, viewDate} = datepicker.picker;
+    let newViewDate;
+    switch (currentView.id) {
+      case 0:
+        newViewDate = addMonths(viewDate, direction);
+        break;
+      case 1:
+        newViewDate = addYears(viewDate, direction);
+        break;
+      default:
+        newViewDate = addYears(viewDate, direction * currentView.navStep);
+    }
+    newViewDate = limitToRange(newViewDate, minDate, maxDate);
+    datepicker.picker.changeFocus(newViewDate).render();
+  }
+
+  function switchView(datepicker) {
+    const viewId = datepicker.picker.currentView.id;
+    if (viewId === datepicker.config.maxView) {
+      return;
+    }
+    datepicker.picker.changeView(viewId + 1).render();
+  }
+
+  function unfocus(datepicker) {
+    if (datepicker.config.updateOnBlur) {
+      datepicker.update({autohide: true});
+    } else {
+      datepicker.refresh('input');
+      datepicker.hide();
+    }
+  }
+
+  function goToSelectedMonthOrYear(datepicker, selection) {
+    const picker = datepicker.picker;
+    const viewDate = new Date(picker.viewDate);
+    const viewId = picker.currentView.id;
+    const newDate = viewId === 1
+      ? addMonths(viewDate, selection - viewDate.getMonth())
+      : addYears(viewDate, selection - viewDate.getFullYear());
+
+    picker.changeFocus(newDate).changeView(viewId - 1).render();
+  }
+
+  function onClickTodayBtn(datepicker) {
+    const picker = datepicker.picker;
+    const currentDate = today();
+    if (datepicker.config.todayBtnMode === 1) {
+      if (datepicker.config.autohide) {
+        datepicker.setDate(currentDate);
         return;
       }
-      datepicker.picker.changeView(viewId + 1).render();
+      datepicker.setDate(currentDate, {render: false});
+      picker.update();
     }
+    if (picker.viewDate !== currentDate) {
+      picker.changeFocus(currentDate);
+    }
+    picker.changeView(0).render();
+  }
 
-    function unfocus(datepicker) {
-      if (datepicker.config.updateOnBlur) {
-        datepicker.update({autohide: true});
-      } else {
-        datepicker.refresh('input');
-        datepicker.hide();
-      }
+  function onClickClearBtn(datepicker) {
+    datepicker.setDate({clear: true});
+  }
+
+  function onClickViewSwitch(datepicker) {
+    switchView(datepicker);
+  }
+
+  function onClickPrevBtn(datepicker) {
+    goToPrevOrNext(datepicker, -1);
+  }
+
+  function onClickNextBtn(datepicker) {
+    goToPrevOrNext(datepicker, 1);
+  }
+
+  // For the picker's main block to delegete the events from `datepicker-cell`s
+  function onClickView(datepicker, ev) {
+    const target = findElementInEventPath(ev, '.datepicker-cell');
+    if (!target || target.classList.contains('disabled')) {
+      return;
     }
 
-    function goToSelectedMonthOrYear(datepicker, selection) {
-      const picker = datepicker.picker;
-      const viewDate = new Date(picker.viewDate);
-      const viewId = picker.currentView.id;
-      const newDate = viewId === 1
-        ? addMonths(viewDate, selection - viewDate.getMonth())
-        : addYears(viewDate, selection - viewDate.getFullYear());
+    const {id, isMinView} = datepicker.picker.currentView;
+    if (isMinView) {
+      datepicker.setDate(Number(target.dataset.date));
+    } else if (id === 1) {
+      goToSelectedMonthOrYear(datepicker, Number(target.dataset.month));
+    } else {
+      goToSelectedMonthOrYear(datepicker, Number(target.dataset.year));
+    }
+  }
 
-      picker.changeFocus(newDate).changeView(viewId - 1).render();
+  function onClickPicker(datepicker) {
+    if (!datepicker.inline && !datepicker.config.disableTouchKeyboard) {
+      datepicker.inputField.focus();
     }
+  }
 
-    function onClickTodayBtn(datepicker) {
-      const picker = datepicker.picker;
-      const currentDate = today();
-      if (datepicker.config.todayBtnMode === 1) {
-        if (datepicker.config.autohide) {
-          datepicker.setDate(currentDate);
-          return;
-        }
-        datepicker.setDate(currentDate, {render: false});
-        picker.update();
+  function processPickerOptions(picker, options) {
+    if (options.title !== undefined) {
+      if (options.title) {
+        picker.controls.title.textContent = options.title;
+        showElement(picker.controls.title);
+      } else {
+        picker.controls.title.textContent = '';
+        hideElement(picker.controls.title);
       }
-      if (picker.viewDate !== currentDate) {
-        picker.changeFocus(currentDate);
+    }
+    if (options.prevArrow) {
+      const prevBtn = picker.controls.prevBtn;
+      emptyChildNodes(prevBtn);
+      options.prevArrow.forEach((node) => {
+        prevBtn.appendChild(node.cloneNode(true));
+      });
+    }
+    if (options.nextArrow) {
+      const nextBtn = picker.controls.nextBtn;
+      emptyChildNodes(nextBtn);
+      options.nextArrow.forEach((node) => {
+        nextBtn.appendChild(node.cloneNode(true));
+      });
+    }
+    if (options.locale) {
+      picker.controls.todayBtn.textContent = options.locale.today;
+      picker.controls.clearBtn.textContent = options.locale.clear;
+    }
+    if (options.todayBtn !== undefined) {
+      if (options.todayBtn) {
+        showElement(picker.controls.todayBtn);
+      } else {
+        hideElement(picker.controls.todayBtn);
       }
-      picker.changeView(0).render();
     }
-
-    function onClickClearBtn(datepicker) {
-      datepicker.setDate({clear: true});
+    if (hasProperty(options, 'minDate') || hasProperty(options, 'maxDate')) {
+      const {minDate, maxDate} = picker.datepicker.config;
+      picker.controls.todayBtn.disabled = !isInRange(today(), minDate, maxDate);
     }
+    if (options.clearBtn !== undefined) {
+      if (options.clearBtn) {
+        showElement(picker.controls.clearBtn);
+      } else {
+        hideElement(picker.controls.clearBtn);
+      }
+    }
+  }
+
+  // Compute view date to reset, which will be...
+  // - the last item of the selected dates or defaultViewDate if no selection
+  // - limitted to minDate or maxDate if it exceeds the range
+  function computeResetViewDate(datepicker) {
+    const {dates, config} = datepicker;
+    const viewDate = dates.length > 0 ? lastItemOf(dates) : config.defaultViewDate;
+    return limitToRange(viewDate, config.minDate, config.maxDate);
+  }
+
+  // Change current view's view date
+  function setViewDate(picker, newDate) {
+    const oldViewDate = new Date(picker.viewDate);
+    const newViewDate = new Date(newDate);
+    const {id, year, first, last} = picker.currentView;
+    const viewYear = newViewDate.getFullYear();
+
+    picker.viewDate = newDate;
+    if (viewYear !== oldViewDate.getFullYear()) {
+      triggerDatepickerEvent(picker.datepicker, 'changeYear');
+    }
+    if (newViewDate.getMonth() !== oldViewDate.getMonth()) {
+      triggerDatepickerEvent(picker.datepicker, 'changeMonth');
+    }
+
+    // return whether the new date is in different period on time from the one
+    // displayed in the current view
+    // when true, the view needs to be re-rendered on the next UI refresh.
+    switch (id) {
+      case 0:
+        return newDate < first || newDate > last;
+      case 1:
+        return viewYear !== year;
+      default:
+        return viewYear < first || viewYear > last;
+    }
+  }
+
+  function getTextDirection(el) {
+    return window.getComputedStyle(el).direction;
+  }
+
+  // Class representing the picker UI
+  class Picker {
+    constructor(datepicker) {
+      this.datepicker = datepicker;
+
+      const template = pickerTemplate.replace(/%buttonClass%/g, datepicker.config.buttonClass);
+      const element = this.element = parseHTML(template).firstChild;
+      const [header, main, footer] = element.firstChild.children;
+      const title = header.firstElementChild;
+      const [prevBtn, viewSwitch, nextBtn] = header.lastElementChild.children;
+      const [todayBtn, clearBtn] = footer.firstChild.children;
+      const controls = {
+        title,
+        prevBtn,
+        viewSwitch,
+        nextBtn,
+        todayBtn,
+        clearBtn,
+      };
+      this.main = main;
+      this.controls = controls;
+
+      const elementClass = datepicker.inline ? 'inline' : 'dropdown';
+      element.classList.add(`datepicker-${elementClass}`);
+
+      processPickerOptions(this, datepicker.config);
+      this.viewDate = computeResetViewDate(datepicker);
+
+      // set up event listeners
+      registerListeners(datepicker, [
+        [element, 'click', onClickPicker.bind(null, datepicker), {capture: true}],
+        [main, 'click', onClickView.bind(null, datepicker)],
+        [controls.viewSwitch, 'click', onClickViewSwitch.bind(null, datepicker)],
+        [controls.prevBtn, 'click', onClickPrevBtn.bind(null, datepicker)],
+        [controls.nextBtn, 'click', onClickNextBtn.bind(null, datepicker)],
+        [controls.todayBtn, 'click', onClickTodayBtn.bind(null, datepicker)],
+        [controls.clearBtn, 'click', onClickClearBtn.bind(null, datepicker)],
+      ]);
+
+      // set up views
+      this.views = [
+        new DaysView(this),
+        new MonthsView(this),
+        new YearsView(this, {id: 2, name: 'years', cellClass: 'year', step: 1}),
+        new YearsView(this, {id: 3, name: 'decades', cellClass: 'decade', step: 10}),
+      ];
+      this.currentView = this.views[datepicker.config.startView];
 
-    function onClickViewSwitch(datepicker) {
-      switchView(datepicker);
+      this.currentView.render();
+      this.main.appendChild(this.currentView.element);
+      datepicker.config.container.appendChild(this.element);
     }
 
-    function onClickPrevBtn(datepicker) {
-      goToPrevOrNext(datepicker, -1);
+    setOptions(options) {
+      processPickerOptions(this, options);
+      this.views.forEach((view) => {
+        view.init(options, false);
+      });
+      this.currentView.render();
     }
 
-    function onClickNextBtn(datepicker) {
-      goToPrevOrNext(datepicker, 1);
+    detach() {
+      this.datepicker.config.container.removeChild(this.element);
     }
 
-    // For the picker's main block to delegete the events from `datepicker-cell`s
-    function onClickView(datepicker, ev) {
-      const target = findElementInEventPath(ev, '.datepicker-cell');
-      if (!target || target.classList.contains('disabled')) {
+    show() {
+      if (this.active) {
         return;
       }
+      this.element.classList.add('active');
+      this.active = true;
 
-      const {id, isMinView} = datepicker.picker.currentView;
-      if (isMinView) {
-        datepicker.setDate(Number(target.dataset.date));
-      } else if (id === 1) {
-        goToSelectedMonthOrYear(datepicker, Number(target.dataset.month));
-      } else {
-        goToSelectedMonthOrYear(datepicker, Number(target.dataset.year));
+      const datepicker = this.datepicker;
+      if (!datepicker.inline) {
+        // ensure picker's direction matches input's
+        const inputDirection = getTextDirection(datepicker.inputField);
+        if (inputDirection !== getTextDirection(datepicker.config.container)) {
+          this.element.dir = inputDirection;
+        } else if (this.element.dir) {
+          this.element.removeAttribute('dir');
+        }
+
+        this.place();
+        if (datepicker.config.disableTouchKeyboard) {
+          datepicker.inputField.blur();
+        }
       }
+      triggerDatepickerEvent(datepicker, 'show');
     }
 
-    function onClickPicker(datepicker) {
-      if (!datepicker.inline && !datepicker.config.disableTouchKeyboard) {
-        datepicker.inputField.focus();
+    hide() {
+      if (!this.active) {
+        return;
       }
-    }
-
-    function processPickerOptions(picker, options) {
-      if (options.title !== undefined) {
-        if (options.title) {
-          picker.controls.title.textContent = options.title;
-          showElement(picker.controls.title);
+      this.datepicker.exitEditMode();
+      this.element.classList.remove('active');
+      this.active = false;
+      triggerDatepickerEvent(this.datepicker, 'hide');
+    }
+
+    place() {
+      const {classList, style} = this.element;
+      const {config, inputField} = this.datepicker;
+      const container = config.container;
+      const {
+        width: calendarWidth,
+        height: calendarHeight,
+      } = this.element.getBoundingClientRect();
+      const {
+        left: containerLeft,
+        top: containerTop,
+        width: containerWidth,
+      } = container.getBoundingClientRect();
+      const {
+        left: inputLeft,
+        top: inputTop,
+        width: inputWidth,
+        height: inputHeight
+      } = inputField.getBoundingClientRect();
+      let {x: orientX, y: orientY} = config.orientation;
+      let scrollTop;
+      let left;
+      let top;
+
+      if (container === document.body) {
+        scrollTop = window.scrollY;
+        left = inputLeft + window.scrollX;
+        top = inputTop + scrollTop;
+      } else {
+        scrollTop = container.scrollTop;
+        left = inputLeft - containerLeft;
+        top = inputTop - containerTop + scrollTop;
+      }
+
+      if (orientX === 'auto') {
+        if (left < 0) {
+          // align to the left and move into visible area if input's left edge < window's
+          orientX = 'left';
+          left = 10;
+        } else if (left + calendarWidth > containerWidth) {
+          // align to the right if canlendar's right edge > container's
+          orientX = 'right';
         } else {
-          picker.controls.title.textContent = '';
-          hideElement(picker.controls.title);
+          orientX = getTextDirection(inputField) === 'rtl' ? 'right' : 'left';
         }
       }
-      if (options.prevArrow) {
-        const prevBtn = picker.controls.prevBtn;
-        emptyChildNodes(prevBtn);
-        options.prevArrow.forEach((node) => {
-          prevBtn.appendChild(node.cloneNode(true));
-        });
-      }
-      if (options.nextArrow) {
-        const nextBtn = picker.controls.nextBtn;
-        emptyChildNodes(nextBtn);
-        options.nextArrow.forEach((node) => {
-          nextBtn.appendChild(node.cloneNode(true));
-        });
-      }
-      if (options.locale) {
-        picker.controls.todayBtn.textContent = options.locale.today;
-        picker.controls.clearBtn.textContent = options.locale.clear;
-      }
-      if (options.todayBtn !== undefined) {
-        if (options.todayBtn) {
-          showElement(picker.controls.todayBtn);
-        } else {
-          hideElement(picker.controls.todayBtn);
-        }
+      if (orientX === 'right') {
+        left -= calendarWidth - inputWidth;
       }
-      if (hasProperty(options, 'minDate') || hasProperty(options, 'maxDate')) {
-        const {minDate, maxDate} = picker.datepicker.config;
-        picker.controls.todayBtn.disabled = !isInRange(today(), minDate, maxDate);
+
+      if (orientY === 'auto') {
+        orientY = top - calendarHeight < scrollTop ? 'bottom' : 'top';
       }
-      if (options.clearBtn !== undefined) {
-        if (options.clearBtn) {
-          showElement(picker.controls.clearBtn);
-        } else {
-          hideElement(picker.controls.clearBtn);
-        }
+      if (orientY === 'top') {
+        top -= calendarHeight;
+      } else {
+        top += inputHeight;
       }
+
+      classList.remove(
+        'datepicker-orient-top',
+        'datepicker-orient-bottom',
+        'datepicker-orient-right',
+        'datepicker-orient-left'
+      );
+      classList.add(`datepicker-orient-${orientY}`, `datepicker-orient-${orientX}`);
+
+      style.top = top ? `${top}px` : top;
+      style.left = left ? `${left}px` : left;
     }
 
-    // Compute view date to reset, which will be...
-    // - the last item of the selected dates or defaultViewDate if no selection
-    // - limitted to minDate or maxDate if it exceeds the range
-    function computeResetViewDate(datepicker) {
-      const {dates, config} = datepicker;
-      const viewDate = dates.length > 0 ? lastItemOf(dates) : config.defaultViewDate;
-      return limitToRange(viewDate, config.minDate, config.maxDate);
+    setViewSwitchLabel(labelText) {
+      this.controls.viewSwitch.textContent = labelText;
     }
 
-    // Change current view's view date
-    function setViewDate(picker, newDate) {
-      const oldViewDate = new Date(picker.viewDate);
-      const newViewDate = new Date(newDate);
-      const {id, year, first, last} = picker.currentView;
-      const viewYear = newViewDate.getFullYear();
+    setPrevBtnDisabled(disabled) {
+      this.controls.prevBtn.disabled = disabled;
+    }
 
-      picker.viewDate = newDate;
-      if (viewYear !== oldViewDate.getFullYear()) {
-        triggerDatepickerEvent(picker.datepicker, 'changeYear');
-      }
-      if (newViewDate.getMonth() !== oldViewDate.getMonth()) {
-        triggerDatepickerEvent(picker.datepicker, 'changeMonth');
-      }
+    setNextBtnDisabled(disabled) {
+      this.controls.nextBtn.disabled = disabled;
+    }
 
-      // return whether the new date is in different period on time from the one
-      // displayed in the current view
-      // when true, the view needs to be re-rendered on the next UI refresh.
-      switch (id) {
-        case 0:
-          return newDate < first || newDate > last;
-        case 1:
-          return viewYear !== year;
-        default:
-          return viewYear < first || viewYear > last;
+    changeView(viewId) {
+      const oldView = this.currentView;
+      const newView =  this.views[viewId];
+      if (newView.id !== oldView.id) {
+        this.currentView = newView;
+        this._renderMethod = 'render';
+        triggerDatepickerEvent(this.datepicker, 'changeView');
+        this.main.replaceChild(newView.element, oldView.element);
       }
+      return this;
     }
 
-    function getTextDirection(el) {
-      return window.getComputedStyle(el).direction;
+    // Change the focused date (view date)
+    changeFocus(newViewDate) {
+      this._renderMethod = setViewDate(this, newViewDate) ? 'render' : 'refreshFocus';
+      this.views.forEach((view) => {
+        view.updateFocus();
+      });
+      return this;
     }
 
-    // Class representing the picker UI
-    class Picker {
-      constructor(datepicker) {
-        this.datepicker = datepicker;
-
-        const template = pickerTemplate.replace(/%buttonClass%/g, datepicker.config.buttonClass);
-        const element = this.element = parseHTML(template).firstChild;
-        const [header, main, footer] = element.firstChild.children;
-        const title = header.firstElementChild;
-        const [prevBtn, viewSwitch, nextBtn] = header.lastElementChild.children;
-        const [todayBtn, clearBtn] = footer.firstChild.children;
-        const controls = {
-          title,
-          prevBtn,
-          viewSwitch,
-          nextBtn,
-          todayBtn,
-          clearBtn,
+    // Apply the change of the selected dates
+    update() {
+      const newViewDate = computeResetViewDate(this.datepicker);
+      this._renderMethod = setViewDate(this, newViewDate) ? 'render' : 'refresh';
+      this.views.forEach((view) => {
+        view.updateFocus();
+        view.updateSelection();
+      });
+      return this;
+    }
+
+    // Refresh the picker UI
+    render(quickRender = true) {
+      const renderMethod = (quickRender && this._renderMethod) || 'render';
+      delete this._renderMethod;
+
+      this.currentView[renderMethod]();
+    }
+  }
+
+  // Find the closest date that doesn't meet the condition for unavailable date
+  // Returns undefined if no available date is found
+  // addFn: function to calculate the next date
+  //   - args: time value, amount
+  // increase: amount to pass to addFn
+  // testFn: function to test the unavailablity of the date
+  //   - args: time value; retun: true if unavailable
+  function findNextAvailableOne(date, addFn, increase, testFn, min, max) {
+    if (!isInRange(date, min, max)) {
+      return;
+    }
+    if (testFn(date)) {
+      const newDate = addFn(date, increase);
+      return findNextAvailableOne(newDate, addFn, increase, testFn, min, max);
+    }
+    return date;
+  }
+
+  // direction: -1 (left/up), 1 (right/down)
+  // vertical: true for up/down, false for left/right
+  function moveByArrowKey(datepicker, ev, direction, vertical) {
+    const picker = datepicker.picker;
+    const currentView = picker.currentView;
+    const step = currentView.step || 1;
+    let viewDate = picker.viewDate;
+    let addFn;
+    let testFn;
+    switch (currentView.id) {
+      case 0:
+        if (vertical) {
+          viewDate = addDays(viewDate, direction * 7);
+        } else if (ev.ctrlKey || ev.metaKey) {
+          viewDate = addYears(viewDate, direction);
+        } else {
+          viewDate = addDays(viewDate, direction);
+        }
+        addFn = addDays;
+        testFn = (date) => currentView.disabled.includes(date);
+        break;
+      case 1:
+        viewDate = addMonths(viewDate, vertical ? direction * 4 : direction);
+        addFn = addMonths;
+        testFn = (date) => {
+          const dt = new Date(date);
+          const {year, disabled} = currentView;
+          return dt.getFullYear() === year && disabled.includes(dt.getMonth());
         };
-        this.main = main;
-        this.controls = controls;
-
-        const elementClass = datepicker.inline ? 'inline' : 'dropdown';
-        element.classList.add(`datepicker-${elementClass}`);
-
-        processPickerOptions(this, datepicker.config);
-        this.viewDate = computeResetViewDate(datepicker);
-
-        // set up event listeners
-        registerListeners(datepicker, [
-          [element, 'click', onClickPicker.bind(null, datepicker), {capture: true}],
-          [main, 'click', onClickView.bind(null, datepicker)],
-          [controls.viewSwitch, 'click', onClickViewSwitch.bind(null, datepicker)],
-          [controls.prevBtn, 'click', onClickPrevBtn.bind(null, datepicker)],
-          [controls.nextBtn, 'click', onClickNextBtn.bind(null, datepicker)],
-          [controls.todayBtn, 'click', onClickTodayBtn.bind(null, datepicker)],
-          [controls.clearBtn, 'click', onClickClearBtn.bind(null, datepicker)],
-        ]);
-
-        // set up views
-        this.views = [
-          new DaysView(this),
-          new MonthsView(this),
-          new YearsView(this, {id: 2, name: 'years', cellClass: 'year', step: 1}),
-          new YearsView(this, {id: 3, name: 'decades', cellClass: 'decade', step: 10}),
-        ];
-        this.currentView = this.views[datepicker.config.startView];
+        break;
+      default:
+        viewDate = addYears(viewDate, direction * (vertical ? 4 : 1) * step);
+        addFn = addYears;
+        testFn = date => currentView.disabled.includes(startOfYearPeriod(date, step));
+    }
+    viewDate = findNextAvailableOne(
+      viewDate,
+      addFn,
+      direction < 0 ? -step : step,
+      testFn,
+      currentView.minDate,
+      currentView.maxDate
+    );
+    if (viewDate !== undefined) {
+      picker.changeFocus(viewDate).render();
+    }
+  }
+
+  function onKeydown(datepicker, ev) {
+    if (ev.key === 'Tab') {
+      unfocus(datepicker);
+      return;
+    }
 
-        this.currentView.render();
-        this.main.appendChild(this.currentView.element);
-        datepicker.config.container.appendChild(this.element);
+    const picker = datepicker.picker;
+    const {id, isMinView} = picker.currentView;
+    if (!picker.active) {
+      switch (ev.key) {
+        case 'ArrowDown':
+        case 'Escape':
+          picker.show();
+          break;
+        case 'Enter':
+          datepicker.update();
+          break;
+        default:
+          return;
       }
-
-      setOptions(options) {
-        processPickerOptions(this, options);
-        this.views.forEach((view) => {
-          view.init(options, false);
-        });
-        this.currentView.render();
+    } else if (datepicker.editMode) {
+      switch (ev.key) {
+        case 'Escape':
+          picker.hide();
+          break;
+        case 'Enter':
+          datepicker.exitEditMode({update: true, autohide: datepicker.config.autohide});
+          break;
+        default:
+          return;
       }
-
-      detach() {
-        this.datepicker.config.container.removeChild(this.element);
+    } else {
+      switch (ev.key) {
+        case 'Escape':
+          picker.hide();
+          break;
+        case 'ArrowLeft':
+          if (ev.ctrlKey || ev.metaKey) {
+            goToPrevOrNext(datepicker, -1);
+          } else if (ev.shiftKey) {
+            datepicker.enterEditMode();
+            return;
+          } else {
+            moveByArrowKey(datepicker, ev, -1, false);
+          }
+          break;
+        case 'ArrowRight':
+          if (ev.ctrlKey || ev.metaKey) {
+            goToPrevOrNext(datepicker, 1);
+          } else if (ev.shiftKey) {
+            datepicker.enterEditMode();
+            return;
+          } else {
+            moveByArrowKey(datepicker, ev, 1, false);
+          }
+          break;
+        case 'ArrowUp':
+          if (ev.ctrlKey || ev.metaKey) {
+            switchView(datepicker);
+          } else if (ev.shiftKey) {
+            datepicker.enterEditMode();
+            return;
+          } else {
+            moveByArrowKey(datepicker, ev, -1, true);
+          }
+          break;
+        case 'ArrowDown':
+          if (ev.shiftKey && !ev.ctrlKey && !ev.metaKey) {
+            datepicker.enterEditMode();
+            return;
+          }
+          moveByArrowKey(datepicker, ev, 1, true);
+          break;
+        case 'Enter':
+          if (isMinView) {
+            datepicker.setDate(picker.viewDate);
+          } else {
+            picker.changeView(id - 1).render();
+          }
+          break;
+        case 'Backspace':
+        case 'Delete':
+          datepicker.enterEditMode();
+          return;
+        default:
+          if (ev.key.length === 1 && !ev.ctrlKey && !ev.metaKey) {
+            datepicker.enterEditMode();
+          }
+          return;
       }
+    }
+    ev.preventDefault();
+    ev.stopPropagation();
+  }
 
-      show() {
-        if (this.active) {
-          return;
-        }
-        this.element.classList.add('active');
-        this.active = true;
+  function onFocus(datepicker) {
+    if (datepicker.config.showOnFocus) {
+      datepicker.show();
+    }
+  }
 
-        const datepicker = this.datepicker;
-        if (!datepicker.inline) {
-          // ensure picker's direction matches input's
-          const inputDirection = getTextDirection(datepicker.inputField);
-          if (inputDirection !== getTextDirection(datepicker.config.container)) {
-            this.element.dir = inputDirection;
-          } else if (this.element.dir) {
-            this.element.removeAttribute('dir');
-          }
+  // for the prevention for entering edit mode while getting focus on click
+  function onMousedown(datepicker, ev) {
+    const el = ev.target;
+    if (datepicker.picker.active || datepicker.config.showOnClick) {
+      el._active = el === document.activeElement;
+      el._clicking = setTimeout(() => {
+        delete el._active;
+        delete el._clicking;
+      }, 2000);
+    }
+  }
 
-          this.place();
-          if (datepicker.config.disableTouchKeyboard) {
-            datepicker.inputField.blur();
-          }
-        }
-        triggerDatepickerEvent(datepicker, 'show');
-      }
+  function onClickInput(datepicker, ev) {
+    const el = ev.target;
+    if (!el._clicking) {
+      return;
+    }
+    clearTimeout(el._clicking);
+    delete el._clicking;
 
-      hide() {
-        if (!this.active) {
-          return;
-        }
-        this.datepicker.exitEditMode();
-        this.element.classList.remove('active');
-        this.active = false;
-        triggerDatepickerEvent(this.datepicker, 'hide');
-      }
-
-      place() {
-        const {classList, style} = this.element;
-        const {config, inputField} = this.datepicker;
-        const container = config.container;
-        const {
-          width: calendarWidth,
-          height: calendarHeight,
-        } = this.element.getBoundingClientRect();
-        const {
-          left: containerLeft,
-          top: containerTop,
-          width: containerWidth,
-        } = container.getBoundingClientRect();
-        const {
-          left: inputLeft,
-          top: inputTop,
-          width: inputWidth,
-          height: inputHeight
-        } = inputField.getBoundingClientRect();
-        let {x: orientX, y: orientY} = config.orientation;
-        let scrollTop;
-        let left;
-        let top;
-
-        if (container === document.body) {
-          scrollTop = window.scrollY;
-          left = inputLeft + window.scrollX;
-          top = inputTop + scrollTop;
-        } else {
-          scrollTop = container.scrollTop;
-          left = inputLeft - containerLeft;
-          top = inputTop - containerTop + scrollTop;
-        }
-
-        if (orientX === 'auto') {
-          if (left < 0) {
-            // align to the left and move into visible area if input's left edge < window's
-            orientX = 'left';
-            left = 10;
-          } else if (left + calendarWidth > containerWidth) {
-            // align to the right if canlendar's right edge > container's
-            orientX = 'right';
-          } else {
-            orientX = getTextDirection(inputField) === 'rtl' ? 'right' : 'left';
-          }
-        }
-        if (orientX === 'right') {
-          left -= calendarWidth - inputWidth;
-        }
+    if (el._active) {
+      datepicker.enterEditMode();
+    }
+    delete el._active;
 
-        if (orientY === 'auto') {
-          orientY = top - calendarHeight < scrollTop ? 'bottom' : 'top';
-        }
-        if (orientY === 'top') {
-          top -= calendarHeight;
-        } else {
-          top += inputHeight;
-        }
+    if (datepicker.config.showOnClick) {
+      datepicker.show();
+    }
+  }
 
-        classList.remove(
-          'datepicker-orient-top',
-          'datepicker-orient-bottom',
-          'datepicker-orient-right',
-          'datepicker-orient-left'
-        );
-        classList.add(`datepicker-orient-${orientY}`, `datepicker-orient-${orientX}`);
+  function onPaste(datepicker, ev) {
+    if (ev.clipboardData.types.includes('text/plain')) {
+      datepicker.enterEditMode();
+    }
+  }
 
-        style.top = top ? `${top}px` : top;
-        style.left = left ? `${left}px` : left;
-      }
+  // for the `document` to delegate the events from outside the picker/input field
+  function onClickOutside(datepicker, ev) {
+    const element = datepicker.element;
+    if (element !== document.activeElement) {
+      return;
+    }
+    const pickerElem = datepicker.picker.element;
+    if (findElementInEventPath(ev, el => el === element || el === pickerElem)) {
+      return;
+    }
+    unfocus(datepicker);
+  }
 
-      setViewSwitchLabel(labelText) {
-        this.controls.viewSwitch.textContent = labelText;
-      }
+  function stringifyDates(dates, config) {
+    return dates
+      .map(dt => formatDate(dt, config.format, config.locale))
+      .join(config.dateDelimiter);
+  }
 
-      setPrevBtnDisabled(disabled) {
-        this.controls.prevBtn.disabled = disabled;
-      }
+  // parse input dates and create an array of time values for selection
+  // returns undefined if there are no valid dates in inputDates
+  // when origDates (current selection) is passed, the function works to mix
+  // the input dates into the current selection
+  function processInputDates(datepicker, inputDates, clear = false) {
+    const {config, dates: origDates, rangepicker} = datepicker;
+      if (inputDates.length === 0) {
+      // empty input is considered valid unless origiDates is passed
+      return clear ? [] : undefined;
+    }
 
-      setNextBtnDisabled(disabled) {
-        this.controls.nextBtn.disabled = disabled;
+    const rangeEnd = rangepicker && datepicker === rangepicker.datepickers[1];
+    let newDates = inputDates.reduce((dates, dt) => {
+      let date = parseDate(dt, config.format, config.locale);
+      if (date === undefined) {
+        return dates;
       }
-
-      changeView(viewId) {
-        const oldView = this.currentView;
-        const newView =  this.views[viewId];
-        if (newView.id !== oldView.id) {
-          this.currentView = newView;
-          this._renderMethod = 'render';
-          triggerDatepickerEvent(this.datepicker, 'changeView');
-          this.main.replaceChild(newView.element, oldView.element);
+      if (config.pickLevel > 0) {
+        // adjust to 1st of the month/Jan 1st of the year
+        // or to the last day of the monh/Dec 31st of the year if the datepicker
+        // is the range-end picker of a rangepicker
+        const dt = new Date(date);
+        if (config.pickLevel === 1) {
+          date = rangeEnd
+            ? dt.setMonth(dt.getMonth() + 1, 0)
+            : dt.setDate(1);
+        } else {
+          date = rangeEnd
+            ? dt.setFullYear(dt.getFullYear() + 1, 0, 0)
+            : dt.setMonth(0, 1);
         }
-        return this;
       }
-
-      // Change the focused date (view date)
-      changeFocus(newViewDate) {
-        this._renderMethod = setViewDate(this, newViewDate) ? 'render' : 'refreshFocus';
-        this.views.forEach((view) => {
-          view.updateFocus();
+      if (
+        isInRange(date, config.minDate, config.maxDate)
+        && !dates.includes(date)
+        && !config.datesDisabled.includes(date)
+        && !config.daysOfWeekDisabled.includes(new Date(date).getDay())
+      ) {
+        dates.push(date);
+      }
+      return dates;
+    }, []);
+    if (newDates.length === 0) {
+      return;
+    }
+    if (config.multidate && !clear) {
+      // get the synmetric difference between origDates and newDates
+      newDates = newDates.reduce((dates, date) => {
+        if (!origDates.includes(date)) {
+          dates.push(date);
+        }
+        return dates;
+      }, origDates.filter(date => !newDates.includes(date)));
+    }
+    // do length check always because user can input multiple dates regardless of the mode
+    return config.maxNumberOfDates && newDates.length > config.maxNumberOfDates
+      ? newDates.slice(config.maxNumberOfDates * -1)
+      : newDates;
+  }
+
+  // refresh the UI elements
+  // modes: 1: input only, 2, picker only, 3 both
+  function refreshUI(datepicker, mode = 3, quickRender = true) {
+    const {config, picker, inputField} = datepicker;
+    if (mode & 2) {
+      const newView = picker.active ? config.pickLevel : config.startView;
+      picker.update().changeView(newView).render(quickRender);
+    }
+    if (mode & 1 && inputField) {
+      inputField.value = stringifyDates(datepicker.dates, config);
+    }
+  }
+
+  function setDate(datepicker, inputDates, options) {
+    let {clear, render, autohide} = options;
+    if (render === undefined) {
+      render = true;
+    }
+    if (!render) {
+      autohide = false;
+    } else if (autohide === undefined) {
+      autohide = datepicker.config.autohide;
+    }
+
+    const newDates = processInputDates(datepicker, inputDates, clear);
+    if (!newDates) {
+      return;
+    }
+    if (newDates.toString() !== datepicker.dates.toString()) {
+      datepicker.dates = newDates;
+      refreshUI(datepicker, render ? 3 : 1);
+      triggerDatepickerEvent(datepicker, 'changeDate');
+    } else {
+      refreshUI(datepicker, 1);
+    }
+    if (autohide) {
+      datepicker.hide();
+    }
+  }
+
+  /**
+   * Class representing a date picker
+   */
+  class Datepicker {
+    /**
+     * Create a date picker
+     * @param  {Element} element - element to bind a date picker
+     * @param  {Object} [options] - config options
+     * @param  {DateRangePicker} [rangepicker] - DateRangePicker instance the
+     * date picker belongs to. Use this only when creating date picker as a part
+     * of date range picker
+     */
+    constructor(element, options = {}, rangepicker = undefined) {
+      element.datepicker = this;
+      this.element = element;
+
+      // set up config
+      const config = this.config = Object.assign({
+        buttonClass: (options.buttonClass && String(options.buttonClass)) || 'button',
+        container: document.body,
+        defaultViewDate: today(),
+        maxDate: undefined,
+        minDate: undefined,
+      }, processOptions(defaultOptions, this));
+      this._options = options;
+      Object.assign(config, processOptions(options, this));
+
+      // configure by type
+      const inline = this.inline = element.tagName !== 'INPUT';
+      let inputField;
+      let initialDates;
+
+      if (inline) {
+        config.container = element;
+        initialDates = stringToArray(element.dataset.date, config.dateDelimiter);
+        delete element.dataset.date;
+      } else {
+        const container = options.container ? document.querySelector(options.container) : null;
+        if (container) {
+          config.container = container;
+        }
+        inputField = this.inputField = element;
+        inputField.classList.add('datepicker-input');
+        initialDates = stringToArray(inputField.value, config.dateDelimiter);
+      }
+      if (rangepicker) {
+        // check validiry
+        const index = rangepicker.inputs.indexOf(inputField);
+        const datepickers = rangepicker.datepickers;
+        if (index < 0 || index > 1 || !Array.isArray(datepickers)) {
+          throw Error('Invalid rangepicker object.');
+        }
+        // attach itaelf to the rangepicker here so that processInputDates() can
+        // determine if this is the range-end picker of the rangepicker while
+        // setting inital values when pickLevel > 0
+        datepickers[index] = this;
+        // add getter for rangepicker
+        Object.defineProperty(this, 'rangepicker', {
+          get() {
+            return rangepicker;
+          },
         });
-        return this;
       }
 
-      // Apply the change of the selected dates
-      update() {
-        const newViewDate = computeResetViewDate(this.datepicker);
-        this._renderMethod = setViewDate(this, newViewDate) ? 'render' : 'refresh';
-        this.views.forEach((view) => {
-          view.updateFocus();
-          view.updateSelection();
-        });
-        return this;
+      // set initial value
+      this.dates = processInputDates(this, initialDates) || [];
+      if (inputField) {
+        inputField.value = stringifyDates(this.dates, config);
       }
 
-      // Refresh the picker UI
-      render(quickRender = true) {
-        const renderMethod = (quickRender && this._renderMethod) || 'render';
-        delete this._renderMethod;
+      const picker = this.picker = new Picker(this);
 
-        this.currentView[renderMethod]();
+      if (inline) {
+        this.show();
+      } else {
+        // set up event listeners in other modes
+        const onMousedownDocument = onClickOutside.bind(null, this);
+        const listeners = [
+          [inputField, 'keydown', onKeydown.bind(null, this)],
+          [inputField, 'focus', onFocus.bind(null, this)],
+          [inputField, 'mousedown', onMousedown.bind(null, this)],
+          [inputField, 'click', onClickInput.bind(null, this)],
+          [inputField, 'paste', onPaste.bind(null, this)],
+          [document, 'mousedown', onMousedownDocument],
+          [document, 'touchstart', onMousedownDocument],
+          [window, 'resize', picker.place.bind(picker)]
+        ];
+        registerListeners(this, listeners);
       }
     }
 
-    // Find the closest date that doesn't meet the condition for unavailable date
-    // Returns undefined if no available date is found
-    // addFn: function to calculate the next date
-    //   - args: time value, amount
-    // increase: amount to pass to addFn
-    // testFn: function to test the unavailablity of the date
-    //   - args: time value; retun: true if unavailable
-    function findNextAvailableOne(date, addFn, increase, testFn, min, max) {
-      if (!isInRange(date, min, max)) {
-        return;
-      }
-      if (testFn(date)) {
-        const newDate = addFn(date, increase);
-        return findNextAvailableOne(newDate, addFn, increase, testFn, min, max);
-      }
-      return date;
+    /**
+     * Format Date object or time value in given format and language
+     * @param  {Date|Number} date - date or time value to format
+     * @param  {String|Object} format - format string or object that contains
+     * toDisplay() custom formatter, whose signature is
+     * - args:
+     *   - date: {Date} - Date instance of the date passed to the method
+     *   - format: {Object} - the format object passed to the method
+     *   - locale: {Object} - locale for the language specified by `lang`
+     * - return:
+     *     {String} formatted date
+     * @param  {String} [lang=en] - language code for the locale to use
+     * @return {String} formatted date
+     */
+    static formatDate(date, format, lang) {
+      return formatDate(date, format, lang && locales[lang] || locales.en);
     }
 
-    // direction: -1 (left/up), 1 (right/down)
-    // vertical: true for up/down, false for left/right
-    function moveByArrowKey(datepicker, ev, direction, vertical) {
-      const picker = datepicker.picker;
-      const currentView = picker.currentView;
-      const step = currentView.step || 1;
-      let viewDate = picker.viewDate;
-      let addFn;
-      let testFn;
-      switch (currentView.id) {
-        case 0:
-          if (vertical) {
-            viewDate = addDays(viewDate, direction * 7);
-          } else if (ev.ctrlKey || ev.metaKey) {
-            viewDate = addYears(viewDate, direction);
-          } else {
-            viewDate = addDays(viewDate, direction);
-          }
-          addFn = addDays;
-          testFn = (date) => currentView.disabled.includes(date);
-          break;
-        case 1:
-          viewDate = addMonths(viewDate, vertical ? direction * 4 : direction);
-          addFn = addMonths;
-          testFn = (date) => {
-            const dt = new Date(date);
-            const {year, disabled} = currentView;
-            return dt.getFullYear() === year && disabled.includes(dt.getMonth());
-          };
-          break;
-        default:
-          viewDate = addYears(viewDate, direction * (vertical ? 4 : 1) * step);
-          addFn = addYears;
-          testFn = date => currentView.disabled.includes(startOfYearPeriod(date, step));
-      }
-      viewDate = findNextAvailableOne(
-        viewDate,
-        addFn,
-        direction < 0 ? -step : step,
-        testFn,
-        currentView.minDate,
-        currentView.maxDate
-      );
-      if (viewDate !== undefined) {
-        picker.changeFocus(viewDate).render();
-      }
+    /**
+     * Parse date string
+     * @param  {String|Date|Number} dateStr - date string, Date object or time
+     * value to parse
+     * @param  {String|Object} format - format string or object that contains
+     * toValue() custom parser, whose signature is
+     * - args:
+     *   - dateStr: {String|Date|Number} - the dateStr passed to the method
+     *   - format: {Object} - the format object passed to the method
+     *   - locale: {Object} - locale for the language specified by `lang`
+     * - return:
+     *     {Date|Number} parsed date or its time value
+     * @param  {String} [lang=en] - language code for the locale to use
+     * @return {Number} time value of parsed date
+     */
+    static parseDate(dateStr, format, lang) {
+      return parseDate(dateStr, format, lang && locales[lang] || locales.en);
     }
 
-    function onKeydown(datepicker, ev) {
-      if (ev.key === 'Tab') {
-        unfocus(datepicker);
-        return;
-      }
-
-      const picker = datepicker.picker;
-      const {id, isMinView} = picker.currentView;
-      if (!picker.active) {
-        switch (ev.key) {
-          case 'ArrowDown':
-          case 'Escape':
-            picker.show();
-            break;
-          case 'Enter':
-            datepicker.update();
-            break;
-          default:
-            return;
-        }
-      } else if (datepicker.editMode) {
-        switch (ev.key) {
-          case 'Escape':
-            picker.hide();
-            break;
-          case 'Enter':
-            datepicker.exitEditMode({update: true, autohide: datepicker.config.autohide});
-            break;
-          default:
-            return;
-        }
-      } else {
-        switch (ev.key) {
-          case 'Escape':
-            picker.hide();
-            break;
-          case 'ArrowLeft':
-            if (ev.ctrlKey || ev.metaKey) {
-              goToPrevOrNext(datepicker, -1);
-            } else if (ev.shiftKey) {
-              datepicker.enterEditMode();
-              return;
-            } else {
-              moveByArrowKey(datepicker, ev, -1, false);
-            }
-            break;
-          case 'ArrowRight':
-            if (ev.ctrlKey || ev.metaKey) {
-              goToPrevOrNext(datepicker, 1);
-            } else if (ev.shiftKey) {
-              datepicker.enterEditMode();
-              return;
-            } else {
-              moveByArrowKey(datepicker, ev, 1, false);
-            }
-            break;
-          case 'ArrowUp':
-            if (ev.ctrlKey || ev.metaKey) {
-              switchView(datepicker);
-            } else if (ev.shiftKey) {
-              datepicker.enterEditMode();
-              return;
-            } else {
-              moveByArrowKey(datepicker, ev, -1, true);
-            }
-            break;
-          case 'ArrowDown':
-            if (ev.shiftKey && !ev.ctrlKey && !ev.metaKey) {
-              datepicker.enterEditMode();
-              return;
-            }
-            moveByArrowKey(datepicker, ev, 1, true);
-            break;
-          case 'Enter':
-            if (isMinView) {
-              datepicker.setDate(picker.viewDate);
-            } else {
-              picker.changeView(id - 1).render();
-            }
-            break;
-          case 'Backspace':
-          case 'Delete':
-            datepicker.enterEditMode();
-            return;
-          default:
-            if (ev.key.length === 1 && !ev.ctrlKey && !ev.metaKey) {
-              datepicker.enterEditMode();
-            }
-            return;
-        }
-      }
-      ev.preventDefault();
-      ev.stopPropagation();
+    /**
+     * @type {Object} - Installed locales in `[languageCode]: localeObject` format
+     * en`:_English (US)_ is pre-installed.
+     */
+    static get locales() {
+      return locales;
     }
 
-    function onFocus(datepicker) {
-      if (datepicker.config.showOnFocus) {
-        datepicker.show();
-      }
+    /**
+     * @type {Boolean} - Whether the picker element is shown. `true` whne shown
+     */
+    get active() {
+      return !!(this.picker && this.picker.active);
     }
 
-    // for the prevention for entering edit mode while getting focus on click
-    function onMousedown(datepicker, ev) {
-      const el = ev.target;
-      if (datepicker.picker.active || datepicker.config.showOnClick) {
-        el._active = el === document.activeElement;
-        el._clicking = setTimeout(() => {
-          delete el._active;
-          delete el._clicking;
-        }, 2000);
-      }
+    /**
+     * @type {HTMLDivElement} - DOM object of picker element
+     */
+    get pickerElement() {
+      return this.picker ? this.picker.element : undefined;
     }
 
-    function onClickInput(datepicker, ev) {
-      const el = ev.target;
-      if (!el._clicking) {
-        return;
-      }
-      clearTimeout(el._clicking);
-      delete el._clicking;
-
-      if (el._active) {
-        datepicker.enterEditMode();
-      }
-      delete el._active;
+    /**
+     * Set new values to the config options
+     * @param {Object} options - config options to update
+     */
+    setOptions(options) {
+      const picker = this.picker;
+      const newOptions = processOptions(options, this);
+      Object.assign(this._options, options);
+      Object.assign(this.config, newOptions);
+      picker.setOptions(newOptions);
 
-      if (datepicker.config.showOnClick) {
-        datepicker.show();
-      }
+      refreshUI(this, 3);
     }
 
-    function onPaste(datepicker, ev) {
-      if (ev.clipboardData.types.includes('text/plain')) {
-        datepicker.enterEditMode();
+    /**
+     * Show the picker element
+     */
+    show() {
+      if (this.inputField && this.inputField.disabled) {
+        return;
       }
+      this.picker.show();
     }
 
-    // for the `document` to delegate the events from outside the picker/input field
-    function onClickOutside(datepicker, ev) {
-      const element = datepicker.element;
-      if (element !== document.activeElement) {
-        return;
-      }
-      const pickerElem = datepicker.picker.element;
-      if (findElementInEventPath(ev, el => el === element || el === pickerElem)) {
+    /**
+     * Hide the picker element
+     * Not available on inline picker
+     */
+    hide() {
+      if (this.inline) {
         return;
       }
-      unfocus(datepicker);
+      this.picker.hide();
+      this.picker.update().changeView(this.config.startView).render();
     }
 
-    function stringifyDates(dates, config) {
-      return dates
-        .map(dt => formatDate(dt, config.format, config.locale))
-        .join(config.dateDelimiter);
+    /**
+     * Destroy the Datepicker instance
+     * @return {Detepicker} - the instance destroyed
+     */
+    destroy() {
+      this.hide();
+      unregisterListeners(this);
+      this.picker.detach();
+      if (!this.inline) {
+        this.inputField.classList.remove('datepicker-input');
+      }
+      delete this.element.datepicker;
+      return this;
     }
 
-    // parse input dates and create an array of time values for selection
-    // returns undefined if there are no valid dates in inputDates
-    // when origDates (current selection) is passed, the function works to mix
-    // the input dates into the current selection
-    function processInputDates(datepicker, inputDates, clear = false) {
-      const {config, dates: origDates, rangepicker} = datepicker;
-        if (inputDates.length === 0) {
-        // empty input is considered valid unless origiDates is passed
-        return clear ? [] : undefined;
-      }
+    /**
+     * Get the selected date(s)
+     *
+     * The method returns a Date object of selected date by default, and returns
+     * an array of selected dates in multidate mode. If format string is passed,
+     * it returns date string(s) formatted in given format.
+     *
+     * @param  {String} [format] - Format string to stringify the date(s)
+     * @return {Date|String|Date[]|String[]} - selected date(s), or if none is
+     * selected, empty array in multidate mode and untitled in sigledate mode
+     */
+    getDate(format = undefined) {
+      const callback = format
+        ? date => formatDate(date, format, this.config.locale)
+        : date => new Date(date);
 
-      const rangeEnd = rangepicker && datepicker === rangepicker.datepickers[1];
-      let newDates = inputDates.reduce((dates, dt) => {
-        let date = parseDate(dt, config.format, config.locale);
-        if (date === undefined) {
-          return dates;
-        }
-        if (config.pickLevel > 0) {
-          // adjust to 1st of the month/Jan 1st of the year
-          // or to the last day of the monh/Dec 31st of the year if the datepicker
-          // is the range-end picker of a rangepicker
-          const dt = new Date(date);
-          if (config.pickLevel === 1) {
-            date = rangeEnd
-              ? dt.setMonth(dt.getMonth() + 1, 0)
-              : dt.setDate(1);
-          } else {
-            date = rangeEnd
-              ? dt.setFullYear(dt.getFullYear() + 1, 0, 0)
-              : dt.setMonth(0, 1);
-          }
-        }
-        if (
-          isInRange(date, config.minDate, config.maxDate)
-          && !dates.includes(date)
-          && !config.datesDisabled.includes(date)
-          && !config.daysOfWeekDisabled.includes(new Date(date).getDay())
-        ) {
-          dates.push(date);
-        }
-        return dates;
-      }, []);
-      if (newDates.length === 0) {
-        return;
+      if (this.config.multidate) {
+        return this.dates.map(callback);
       }
-      if (config.multidate && !clear) {
-        // get the synmetric difference between origDates and newDates
-        newDates = newDates.reduce((dates, date) => {
-          if (!origDates.includes(date)) {
-            dates.push(date);
-          }
-          return dates;
-        }, origDates.filter(date => !newDates.includes(date)));
+      if (this.dates.length > 0) {
+        return callback(this.dates[0]);
       }
-      // do length check always because user can input multiple dates regardless of the mode
-      return config.maxNumberOfDates && newDates.length > config.maxNumberOfDates
-        ? newDates.slice(config.maxNumberOfDates * -1)
-        : newDates;
     }
 
-    // refresh the UI elements
-    // modes: 1: input only, 2, picker only, 3 both
-    function refreshUI(datepicker, mode = 3, quickRender = true) {
-      const {config, picker, inputField} = datepicker;
-      if (mode & 2) {
-        const newView = picker.active ? config.pickLevel : config.startView;
-        picker.update().changeView(newView).render(quickRender);
-      }
-      if (mode & 1 && inputField) {
-        inputField.value = stringifyDates(datepicker.dates, config);
+    /**
+     * Set selected date(s)
+     *
+     * In multidate mode, you can pass multiple dates as a series of arguments
+     * or an array. (Since each date is parsed individually, the type of the
+     * dates doesn't have to be the same.)
+     * The given dates are used to toggle the select status of each date. The
+     * number of selected dates is kept from exceeding the length set to
+     * maxNumberOfDates.
+     *
+     * With clear: true option, the method can be used to clear the selection
+     * and to replace the selection instead of toggling in multidate mode.
+     * If the option is passed with no date arguments or an empty dates array,
+     * it works as "clear" (clear the selection then set nothing), and if the
+     * option is passed with new dates to select, it works as "replace" (clear
+     * the selection then set the given dates)
+     *
+     * When render: false option is used, the method omits re-rendering the
+     * picker element. In this case, you need to call refresh() method later in
+     * order for the picker element to reflect the changes. The input field is
+     * refreshed always regardless of this option.
+     *
+     * When invalid (unparsable, repeated, disabled or out-of-range) dates are
+     * passed, the method ignores them and applies only valid ones. In the case
+     * that all the given dates are invalid, which is distinguished from passing
+     * no dates, the method considers it as an error and leaves the selection
+     * untouched.
+     *
+     * @param {...(Date|Number|String)|Array} [dates] - Date strings, Date
+     * objects, time values or mix of those for new selection
+     * @param {Object} [options] - function options
+     * - clear: {boolean} - Whether to clear the existing selection
+     *     defualt: false
+     * - render: {boolean} - Whether to re-render the picker element
+     *     default: true
+     * - autohide: {boolean} - Whether to hide the picker element after re-render
+     *     Ignored when used with render: false
+     *     default: config.autohide
+     */
+    setDate(...args) {
+      const dates = [...args];
+      const opts = {};
+      const lastArg = lastItemOf(args);
+      if (
+        typeof lastArg === 'object'
+        && !Array.isArray(lastArg)
+        && !(lastArg instanceof Date)
+        && lastArg
+      ) {
+        Object.assign(opts, dates.pop());
       }
+
+      const inputDates = Array.isArray(dates[0]) ? dates[0] : dates;
+      setDate(this, inputDates, opts);
     }
 
-    function setDate(datepicker, inputDates, options) {
-      let {clear, render, autohide} = options;
-      if (render === undefined) {
-        render = true;
-      }
-      if (!render) {
-        autohide = false;
-      } else if (autohide === undefined) {
-        autohide = datepicker.config.autohide;
+    /**
+     * Update the selected date(s) with input field's value
+     * Not available on inline picker
+     *
+     * The input field will be refreshed with properly formatted date string.
+     *
+     * @param  {Object} [options] - function options
+     * - autohide: {boolean} - whether to hide the picker element after refresh
+     *     default: false
+     */
+    update(options = undefined) {
+      if (this.inline) {
+        return;
       }
 
-      const newDates = processInputDates(datepicker, inputDates, clear);
-      if (!newDates) {
-        return;
+      const opts = {clear: true, autohide: !!(options && options.autohide)};
+      const inputDates = stringToArray(this.inputField.value, this.config.dateDelimiter);
+      setDate(this, inputDates, opts);
+    }
+
+    /**
+     * Refresh the picker element and the associated input field
+     * @param {String} [target] - target item when refreshing one item only
+     * 'picker' or 'input'
+     * @param {Boolean} [forceRender] - whether to re-render the picker element
+     * regardless of its state instead of optimized refresh
+     */
+    refresh(target = undefined, forceRender = false) {
+      if (target && typeof target !== 'string') {
+        forceRender = target;
+        target = undefined;
       }
-      if (newDates.toString() !== datepicker.dates.toString()) {
-        datepicker.dates = newDates;
-        refreshUI(datepicker, render ? 3 : 1);
-        triggerDatepickerEvent(datepicker, 'changeDate');
+
+      let mode;
+      if (target === 'picker') {
+        mode = 2;
+      } else if (target === 'input') {
+        mode = 1;
       } else {
-        refreshUI(datepicker, 1);
+        mode = 3;
       }
-      if (autohide) {
-        datepicker.hide();
+      refreshUI(this, mode, !forceRender);
+    }
+
+    /**
+     * Enter edit mode
+     * Not available on inline picker or when the picker element is hidden
+     */
+    enterEditMode() {
+      if (this.inline || !this.picker.active || this.editMode) {
+        return;
       }
+      this.editMode = true;
+      this.inputField.classList.add('in-edit');
     }
 
     /**
-     * Class representing a date picker
+     * Exit from edit mode
+     * Not available on inline picker
+     * @param  {Object} [options] - function options
+     * - update: {boolean} - whether to call update() after exiting
+     *     If false, input field is revert to the existing selection
+     *     default: false
      */
-    class Datepicker {
-      /**
-       * Create a date picker
-       * @param  {Element} element - element to bind a date picker
-       * @param  {Object} [options] - config options
-       * @param  {DateRangePicker} [rangepicker] - DateRangePicker instance the
-       * date picker belongs to. Use this only when creating date picker as a part
-       * of date range picker
-       */
-      constructor(element, options = {}, rangepicker = undefined) {
-        element.datepicker = this;
-        this.element = element;
-
-        // set up config
-        const config = this.config = Object.assign({
-          buttonClass: (options.buttonClass && String(options.buttonClass)) || 'button',
-          container: document.body,
-          defaultViewDate: today(),
-          maxDate: undefined,
-          minDate: undefined,
-        }, processOptions(defaultOptions, this));
-        this._options = options;
-        Object.assign(config, processOptions(options, this));
-
-        // configure by type
-        const inline = this.inline = element.tagName !== 'INPUT';
-        let inputField;
-        let initialDates;
-
-        if (inline) {
-          config.container = element;
-          initialDates = stringToArray(element.dataset.date, config.dateDelimiter);
-          delete element.dataset.date;
-        } else {
-          const container = options.container ? document.querySelector(options.container) : null;
-          if (container) {
-            config.container = container;
-          }
-          inputField = this.inputField = element;
-          inputField.classList.add('datepicker-input');
-          initialDates = stringToArray(inputField.value, config.dateDelimiter);
-        }
-        if (rangepicker) {
-          // check validiry
-          const index = rangepicker.inputs.indexOf(inputField);
-          const datepickers = rangepicker.datepickers;
-          if (index < 0 || index > 1 || !Array.isArray(datepickers)) {
-            throw Error('Invalid rangepicker object.');
-          }
-          // attach itaelf to the rangepicker here so that processInputDates() can
-          // determine if this is the range-end picker of the rangepicker while
-          // setting inital values when pickLevel > 0
-          datepickers[index] = this;
-          // add getter for rangepicker
-          Object.defineProperty(this, 'rangepicker', {
-            get() {
-              return rangepicker;
-            },
-          });
-        }
+    exitEditMode(options = undefined) {
+      if (this.inline || !this.editMode) {
+        return;
+      }
+      const opts = Object.assign({update: false}, options);
+      delete this.editMode;
+      this.inputField.classList.remove('in-edit');
+      if (opts.update) {
+        this.update(opts);
+      }
+    }
+  }
+
+  /*
+   * Licensed to the Apache Software Foundation (ASF) under one or more
+   * contributor license agreements.  See the NOTICE file distributed with
+   * this work for additional information regarding copyright ownership.
+   * The ASF licenses this file to You under the Apache License, Version 2.0
+   * (the "License"); you may not use this file except in compliance with
+   * the License.  You may obtain a copy of the License at
+   *
+   *      http://www.apache.org/licenses/LICENSE-2.0
+   *
+   * Unless required by applicable law or agreed to in writing, software
+   * distributed under the License is distributed on an "AS IS" BASIS,
+   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   * See the License for the specific language governing permissions and
+   * limitations under the License.
+   */
+  class Config {
+      static set(key, value) {
+          this.map.set(key, value);
+      }
+      static get(key) {
+          const value = this.map.get(key);
+          if (value) {
+              return value;
+          }
+          else {
+              console.warn("Config.get(" + key + ") = undefined");
+              return 0;
+          }
+      }
+  }
+  Config.map = new Map();
+
+  /*
+   * Licensed to the Apache Software Foundation (ASF) under one or more
+   * contributor license agreements.  See the NOTICE file distributed with
+   * this work for additional information regarding copyright ownership.
+   * The ASF licenses this file to You under the Apache License, Version 2.0
+   * (the "License"); you may not use this file except in compliance with
+   * the License.  You may obtain a copy of the License at
+   *
+   *      http://www.apache.org/licenses/LICENSE-2.0
+   *
+   * Unless required by applicable law or agreed to in writing, software
+   * distributed under the License is distributed on an "AS IS" BASIS,
+   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   * See the License for the specific language governing permissions and
+   * limitations under the License.
+   */
+  // XXX issue: if a ajax call is scheduled on the same element, the animation arrow will stacking and not desapearing.
+  // XXX issue: "error" is not implemented correctly
+  // see http://localhost:8080/demo-5-snapshot/content/30-concept/50-partial/Partial_Ajax.xhtml to use this feature
+  // XXX todo: check full page transitions
+  class Overlay {
+      constructor(element, ajax = false, error = false, waitOverlayDelay) {
+          /**
+           * Is this overlay for an AJAX request, or an normal submit?
+           * We need this information, because AJAX need to clone the animated image, but for a normal submit
+           * we must not clone it, because the animation stops in some browsers.
+           */
+          this.ajax = true;
+          /**
+           * This boolean indicates, if the overlay is "error" or "wait".
+           */
+          this.error = false;
+          /**
+           * The delay for the wait overlay. If not set the default delay is read from Tobago.Config.
+           */
+          this.waitOverlayDelay = 0;
+          this.element = element;
+          this.ajax = ajax;
+          this.error = error;
+          this.waitOverlayDelay = waitOverlayDelay
+              ? waitOverlayDelay
+              : Config.get(this.ajax ? "Ajax.waitOverlayDelay" : "Tobago.waitOverlayDelay");
+          // create the overlay
+          this.overlay = document.createElement("div");
+          this.overlay.classList.add("tobago-page-overlay");
+          this.overlay.classList.add(this.error ? "tobago-page-overlay-markup-error" : null);
+          let left = "0";
+          let top = "0";
+          if (this.element.matches("body")) {
+              this.overlay.style.position = "fixed";
+              this.overlay.style.zIndex = "1500"; // greater than the bootstrap navbar
+          }
+          else {
+              const rect = this.element.getBoundingClientRect();
+              left = (rect.left + document.body.scrollLeft) + "px";
+              top = (rect.top + document.body.scrollTop) + "px";
+              this.overlay.style.width = this.element.offsetWidth + "px";
+              this.overlay.style.height = this.element.offsetHeight + "px";
+              // tbd: is this still needed?       this.overlay.style.position= "absolute"
+              // XXX is set via class, but seams to be overridden in IE11?
+          }
+          document.getElementsByTagName("body")[0].append(this.overlay);
+          let wait = document.createElement("div");
+          wait.classList.add("tobago-page-overlayCenter");
+          this.overlay.append(wait);
+          let image = document.createElement("i");
+          if (this.error) {
+              image.classList.add("fa", "fa-flash", "fa-3x");
+              wait.classList.add("alert-danger");
+          }
+          else {
+              image.classList.add("fa", "fa-refresh", "fa-3x", "fa-spin");
+              image.style.opacity = "0.4";
+          }
+          wait.append(image);
+          wait.style.display = ""; //XXX ?
+          this.overlay.style.backgroundColor = Page.page(this.element).style.backgroundColor;
+          this.overlay.style.left = left;
+          this.overlay.style.top = top;
+          setTimeout(() => {
+              this.overlay.classList.add("tobago-page-overlay-timeout");
+          }, this.waitOverlayDelay);
+          Overlay.overlayMap.set(element.id, this);
+          console.debug("----> set overlay " + element.id);
+      }
+      static destroy(id) {
+          console.debug("----> get overlay " + id);
+          const overlay = Overlay.overlayMap.get(id);
+          if (overlay) {
+              overlay.overlay.remove();
+              Overlay.overlayMap.delete(id);
+          }
+          else {
+              console.warn("Overlay not found for id='" + id + "'");
+          }
+      }
+  }
+  Overlay.overlayMap = new Map();
+  Config.set("Tobago.waitOverlayDelay", 1000);
+  Config.set("Ajax.waitOverlayDelay", 1000);
+
+  var top = 'top';
+  var bottom = 'bottom';
+  var right = 'right';
+  var left = 'left';
+  var auto = 'auto';
+  var basePlacements = [top, bottom, right, left];
+  var start = 'start';
+  var end = 'end';
+  var clippingParents = 'clippingParents';
+  var viewport = 'viewport';
+  var popper = 'popper';
+  var reference = 'reference';
+  var variationPlacements = /*#__PURE__*/basePlacements.reduce(function (acc, placement) {
+    return acc.concat([placement + "-" + start, placement + "-" + end]);
+  }, []);
+  var placements = /*#__PURE__*/[].concat(basePlacements, [auto]).reduce(function (acc, placement) {
+    return acc.concat([placement, placement + "-" + start, placement + "-" + end]);
+  }, []); // modifiers that need to read the DOM
+
+  var beforeRead = 'beforeRead';
+  var read = 'read';
+  var afterRead = 'afterRead'; // pure-logic modifiers
+
+  var beforeMain = 'beforeMain';
+  var main = 'main';
+  var afterMain = 'afterMain'; // modifier with the purpose to write to the DOM (or write into a framework state)
+
+  var beforeWrite = 'beforeWrite';
+  var write = 'write';
+  var afterWrite = 'afterWrite';
+  var modifierPhases = [beforeRead, read, afterRead, beforeMain, main, afterMain, beforeWrite, write, afterWrite];
+
+  function getNodeName(element) {
+    return element ? (element.nodeName || '').toLowerCase() : null;
+  }
+
+  /*:: import type { Window } from '../types'; */
+
+  /*:: declare function getWindow(node: Node | Window): Window; */
+  function getWindow(node) {
+    if (node.toString() !== '[object Window]') {
+      var ownerDocument = node.ownerDocument;
+      return ownerDocument ? ownerDocument.defaultView || window : window;
+    }
+
+    return node;
+  }
+
+  /*:: declare function isElement(node: mixed): boolean %checks(node instanceof
+    Element); */
+
+  function isElement(node) {
+    var OwnElement = getWindow(node).Element;
+    return node instanceof OwnElement || node instanceof Element;
+  }
+  /*:: declare function isHTMLElement(node: mixed): boolean %checks(node instanceof
+    HTMLElement); */
+
+
+  function isHTMLElement(node) {
+    var OwnElement = getWindow(node).HTMLElement;
+    return node instanceof OwnElement || node instanceof HTMLElement;
+  }
+  /*:: declare function isShadowRoot(node: mixed): boolean %checks(node instanceof
+    ShadowRoot); */
+
+
+  function isShadowRoot(node) {
+    // IE 11 has no ShadowRoot
+    if (typeof ShadowRoot === 'undefined') {
+      return false;
+    }
 
-        // set initial value
-        this.dates = processInputDates(this, initialDates) || [];
-        if (inputField) {
-          inputField.value = stringifyDates(this.dates, config);
-        }
+    var OwnElement = getWindow(node).ShadowRoot;
+    return node instanceof OwnElement || node instanceof ShadowRoot;
+  }
 
-        const picker = this.picker = new Picker(this);
+  // and applies them to the HTMLElements such as popper and arrow
 
-        if (inline) {
-          this.show();
-        } else {
-          // set up event listeners in other modes
-          const onMousedownDocument = onClickOutside.bind(null, this);
-          const listeners = [
-            [inputField, 'keydown', onKeydown.bind(null, this)],
-            [inputField, 'focus', onFocus.bind(null, this)],
-            [inputField, 'mousedown', onMousedown.bind(null, this)],
-            [inputField, 'click', onClickInput.bind(null, this)],
-            [inputField, 'paste', onPaste.bind(null, this)],
-            [document, 'mousedown', onMousedownDocument],
-            [document, 'touchstart', onMousedownDocument],
-            [window, 'resize', picker.place.bind(picker)]
-          ];
-          registerListeners(this, listeners);
-        }
-      }
+  function applyStyles(_ref) {
+    var state = _ref.state;
+    Object.keys(state.elements).forEach(function (name) {
+      var style = state.styles[name] || {};
+      var attributes = state.attributes[name] || {};
+      var element = state.elements[name]; // arrow is optional + virtual elements
 
-      /**
-       * Format Date object or time value in given format and language
-       * @param  {Date|Number} date - date or time value to format
-       * @param  {String|Object} format - format string or object that contains
-       * toDisplay() custom formatter, whose signature is
-       * - args:
-       *   - date: {Date} - Date instance of the date passed to the method
-       *   - format: {Object} - the format object passed to the method
-       *   - locale: {Object} - locale for the language specified by `lang`
-       * - return:
-       *     {String} formatted date
-       * @param  {String} [lang=en] - language code for the locale to use
-       * @return {String} formatted date
-       */
-      static formatDate(date, format, lang) {
-        return formatDate(date, format, lang && locales[lang] || locales.en);
-      }
+      if (!isHTMLElement(element) || !getNodeName(element)) {
+        return;
+      } // Flow doesn't support to extend this property, but it's the most
+      // effective way to apply styles to an HTMLElement
+      // $FlowFixMe[cannot-write]
 
-      /**
-       * Parse date string
-       * @param  {String|Date|Number} dateStr - date string, Date object or time
-       * value to parse
-       * @param  {String|Object} format - format string or object that contains
-       * toValue() custom parser, whose signature is
-       * - args:
-       *   - dateStr: {String|Date|Number} - the dateStr passed to the method
-       *   - format: {Object} - the format object passed to the method
-       *   - locale: {Object} - locale for the language specified by `lang`
-       * - return:
-       *     {Date|Number} parsed date or its time value
-       * @param  {String} [lang=en] - language code for the locale to use
-       * @return {Number} time value of parsed date
-       */
-      static parseDate(dateStr, format, lang) {
-        return parseDate(dateStr, format, lang && locales[lang] || locales.en);
-      }
 
-      /**
-       * @type {Object} - Installed locales in `[languageCode]: localeObject` format
-       * en`:_English (US)_ is pre-installed.
-       */
-      static get locales() {
-        return locales;
-      }
+      Object.assign(element.style, style);
+      Object.keys(attributes).forEach(function (name) {
+        var value = attributes[name];
 
-      /**
-       * @type {Boolean} - Whether the picker element is shown. `true` whne shown
-       */
-      get active() {
-        return !!(this.picker && this.picker.active);
-      }
+        if (value === false) {
+          element.removeAttribute(name);
+        } else {
+          element.setAttribute(name, value === true ? '' : value);
+        }
+      });
+    });
+  }
+
+  function effect(_ref2) {
+    var state = _ref2.state;
+    var initialStyles = {
+      popper: {
+        position: state.options.strategy,
+        left: '0',
+        top: '0',
+        margin: '0'
+      },
+      arrow: {
+        position: 'absolute'
+      },
+      reference: {}
+    };
+    Object.assign(state.elements.popper.style, initialStyles.popper);
+    state.styles = initialStyles;
 
-      /**
-       * @type {HTMLDivElement} - DOM object of picker element
-       */
-      get pickerElement() {
-        return this.picker ? this.picker.element : undefined;
-      }
+    if (state.elements.arrow) {
+      Object.assign(state.elements.arrow.style, initialStyles.arrow);
+    }
 
-      /**
-       * Set new values to the config options
-       * @param {Object} options - config options to update
-       */
-      setOptions(options) {
-        const picker = this.picker;
-        const newOptions = processOptions(options, this);
-        Object.assign(this._options, options);
-        Object.assign(this.config, newOptions);
-        picker.setOptions(newOptions);
+    return function () {
+      Object.keys(state.elements).forEach(function (name) {
+        var element = state.elements[name];
+        var attributes = state.attributes[name] || {};
+        var styleProperties = Object.keys(state.styles.hasOwnProperty(name) ? state.styles[name] : initialStyles[name]); // Set all values to an empty string to unset them
 
-        refreshUI(this, 3);
-      }
+        var style = styleProperties.reduce(function (style, property) {
+          style[property] = '';
+          return style;
+        }, {}); // arrow is optional + virtual elements
 
-      /**
-       * Show the picker element
-       */
-      show() {
-        if (this.inputField && this.inputField.disabled) {
+        if (!isHTMLElement(element) || !getNodeName(element)) {
           return;
         }
-        this.picker.show();
-      }
 
-      /**
-       * Hide the picker element
-       * Not available on inline picker
-       */
-      hide() {
-        if (this.inline) {
-          return;
-        }
-        this.picker.hide();
-        this.picker.update().changeView(this.config.startView).render();
-      }
+        Object.assign(element.style, style);
+        Object.keys(attributes).forEach(function (attribute) {
+          element.removeAttribute(attribute);
+        });
+      });
+    };
+  } // eslint-disable-next-line import/no-unused-modules
+
+
+  var applyStyles$1 = {
+    name: 'applyStyles',
+    enabled: true,
+    phase: 'write',
+    fn: applyStyles,
+    effect: effect,
+    requires: ['computeStyles']
+  };
+
+  function getBasePlacement(placement) {
+    return placement.split('-')[0];
+  }
+
+  // Returns the layout rect of an element relative to its offsetParent. Layout
+  // means it doesn't take into account transforms.
+  function getLayoutRect(element) {
+    return {
+      x: element.offsetLeft,
+      y: element.offsetTop,
+      width: element.offsetWidth,
+      height: element.offsetHeight
+    };
+  }
 
-      /**
-       * Destroy the Datepicker instance
-       * @return {Detepicker} - the instance destroyed
-       */
-      destroy() {
-        this.hide();
-        unregisterListeners(this);
-        this.picker.detach();
-        if (!this.inline) {
-          this.inputField.classList.remove('datepicker-input');
-        }
-        delete this.element.datepicker;
-        return this;
-      }
+  function contains(parent, child) {
+    var rootNode = child.getRootNode && child.getRootNode(); // First, attempt with faster native method
 
-      /**
-       * Get the selected date(s)
-       *
-       * The method returns a Date object of selected date by default, and returns
-       * an array of selected dates in multidate mode. If format string is passed,
-       * it returns date string(s) formatted in given format.
-       *
-       * @param  {String} [format] - Format string to stringify the date(s)
-       * @return {Date|String|Date[]|String[]} - selected date(s), or if none is
-       * selected, empty array in multidate mode and untitled in sigledate mode
-       */
-      getDate(format = undefined) {
-        const callback = format
-          ? date => formatDate(date, format, this.config.locale)
-          : date => new Date(date);
+    if (parent.contains(child)) {
+      return true;
+    } // then fallback to custom implementation with Shadow DOM support
+    else if (rootNode && isShadowRoot(rootNode)) {
+        var next = child;
 
-        if (this.config.multidate) {
-          return this.dates.map(callback);
-        }
-        if (this.dates.length > 0) {
-          return callback(this.dates[0]);
-        }
-      }
+        do {
+          if (next && parent.isSameNode(next)) {
+            return true;
+          } // $FlowFixMe[prop-missing]: need a better way to handle this...
 
-      /**
-       * Set selected date(s)
-       *
-       * In multidate mode, you can pass multiple dates as a series of arguments
-       * or an array. (Since each date is parsed individually, the type of the
-       * dates doesn't have to be the same.)
-       * The given dates are used to toggle the select status of each date. The
-       * number of selected dates is kept from exceeding the length set to
-       * maxNumberOfDates.
-       *
-       * With clear: true option, the method can be used to clear the selection
-       * and to replace the selection instead of toggling in multidate mode.
-       * If the option is passed with no date arguments or an empty dates array,
-       * it works as "clear" (clear the selection then set nothing), and if the
-       * option is passed with new dates to select, it works as "replace" (clear
-       * the selection then set the given dates)
-       *
-       * When render: false option is used, the method omits re-rendering the
-       * picker element. In this case, you need to call refresh() method later in
-       * order for the picker element to reflect the changes. The input field is
-       * refreshed always regardless of this option.
-       *
-       * When invalid (unparsable, repeated, disabled or out-of-range) dates are
-       * passed, the method ignores them and applies only valid ones. In the case
-       * that all the given dates are invalid, which is distinguished from passing
-       * no dates, the method considers it as an error and leaves the selection
-       * untouched.
-       *
-       * @param {...(Date|Number|String)|Array} [dates] - Date strings, Date
-       * objects, time values or mix of those for new selection
-       * @param {Object} [options] - function options
-       * - clear: {boolean} - Whether to clear the existing selection
-       *     defualt: false
-       * - render: {boolean} - Whether to re-render the picker element
-       *     default: true
-       * - autohide: {boolean} - Whether to hide the picker element after re-render
-       *     Ignored when used with render: false
-       *     default: config.autohide
-       */
-      setDate(...args) {
-        const dates = [...args];
-        const opts = {};
-        const lastArg = lastItemOf(args);
-        if (
-          typeof lastArg === 'object'
-          && !Array.isArray(lastArg)
-          && !(lastArg instanceof Date)
-          && lastArg
-        ) {
-          Object.assign(opts, dates.pop());
-        }
 
-        const inputDates = Array.isArray(dates[0]) ? dates[0] : dates;
-        setDate(this, inputDates, opts);
-      }
+          next = next.parentNode || next.host;
+        } while (next);
+      } // Give up, the result is false
 
-      /**
-       * Update the selected date(s) with input field's value
-       * Not available on inline picker
-       *
-       * The input field will be refreshed with properly formatted date string.
-       *
-       * @param  {Object} [options] - function options
-       * - autohide: {boolean} - whether to hide the picker element after refresh
-       *     default: false
-       */
-      update(options = undefined) {
-        if (this.inline) {
-          return;
-        }
 
-        const opts = {clear: true, autohide: !!(options && options.autohide)};
-        const inputDates = stringToArray(this.inputField.value, this.config.dateDelimiter);
-        setDate(this, inputDates, opts);
-      }
+    return false;
+  }
 
-      /**
-       * Refresh the picker element and the associated input field
-       * @param {String} [target] - target item when refreshing one item only
-       * 'picker' or 'input'
-       * @param {Boolean} [forceRender] - whether to re-render the picker element
-       * regardless of its state instead of optimized refresh
-       */
-      refresh(target = undefined, forceRender = false) {
-        if (target && typeof target !== 'string') {
-          forceRender = target;
-          target = undefined;
-        }
+  function getComputedStyle$1(element) {
+    return getWindow(element).getComputedStyle(element);
+  }
 
-        let mode;
-        if (target === 'picker') {
-          mode = 2;
-        } else if (target === 'input') {
-          mode = 1;
-        } else {
-          mode = 3;
-        }
-        refreshUI(this, mode, !forceRender);
-      }
+  function isTableElement(element) {
+    return ['table', 'td', 'th'].indexOf(getNodeName(element)) >= 0;
+  }
 
-      /**
-       * Enter edit mode
-       * Not available on inline picker or when the picker element is hidden
-       */
-      enterEditMode() {
-        if (this.inline || !this.picker.active || this.editMode) {
-          return;
-        }
-        this.editMode = true;
-        this.inputField.classList.add('in-edit');
-      }
+  function getDocumentElement(element) {
+    // $FlowFixMe[incompatible-return]: assume body is always available
+    return ((isElement(element) ? element.ownerDocument : // $FlowFixMe[prop-missing]
+    element.document) || window.document).documentElement;
+  }
 
-      /**
-       * Exit from edit mode
-       * Not available on inline picker
-       * @param  {Object} [options] - function options
-       * - update: {boolean} - whether to call update() after exiting
-       *     If false, input field is revert to the existing selection
-       *     default: false
-       */
-      exitEditMode(options = undefined) {
-        if (this.inline || !this.editMode) {
-          return;
-        }
-        const opts = Object.assign({update: false}, options);
-        delete this.editMode;
-        this.inputField.classList.remove('in-edit');
-        if (opts.update) {
-          this.update(opts);
-        }
-      }
+  function getParentNode(element) {
+    if (getNodeName(element) === 'html') {
+      return element;
     }
 
-    /*
-     * Licensed to the Apache Software Foundation (ASF) under one or more
-     * contributor license agreements.  See the NOTICE file distributed with
-     * this work for additional information regarding copyright ownership.
-     * The ASF licenses this file to You under the Apache License, Version 2.0
-     * (the "License"); you may not use this file except in compliance with
-     * the License.  You may obtain a copy of the License at
-     *
-     *      http://www.apache.org/licenses/LICENSE-2.0
-     *
-     * Unless required by applicable law or agreed to in writing, software
-     * distributed under the License is distributed on an "AS IS" BASIS,
-     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     * See the License for the specific language governing permissions and
-     * limitations under the License.
-     */
-    class Config {
-        static set(key, value) {
-            this.map.set(key, value);
-        }
-        static get(key) {
-            const value = this.map.get(key);
-            if (value) {
-                return value;
-            }
-            else {
-                console.warn("Config.get(" + key + ") = undefined");
-                return 0;
-            }
-        }
-    }
-    Config.map = new Map();
+    return (// this is a quicker (but less type safe) way to save quite some bytes from the bundle
+      // $FlowFixMe[incompatible-return]
+      // $FlowFixMe[prop-missing]
+      element.assignedSlot || // step into the shadow DOM of the parent of a slotted node
+      element.parentNode || ( // DOM Element detected
+      isShadowRoot(element) ? element.host : null) || // ShadowRoot detected
+      // $FlowFixMe[incompatible-call]: HTMLElement is a Node
+      getDocumentElement(element) // fallback
 
-    /*
-     * Licensed to the Apache Software Foundation (ASF) under one or more
-     * contributor license agreements.  See the NOTICE file distributed with
-     * this work for additional information regarding copyright ownership.
-     * The ASF licenses this file to You under the Apache License, Version 2.0
-     * (the "License"); you may not use this file except in compliance with
-     * the License.  You may obtain a copy of the License at
-     *
-     *      http://www.apache.org/licenses/LICENSE-2.0
-     *
-     * Unless required by applicable law or agreed to in writing, software
-     * distributed under the License is distributed on an "AS IS" BASIS,
-     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     * See the License for the specific language governing permissions and
-     * limitations under the License.
-     */
-    // XXX issue: if a ajax call is scheduled on the same element, the animation arrow will stacking and not desapearing.
-    // XXX issue: "error" is not implemented correctly
-    // see http://localhost:8080/demo-5-snapshot/content/30-concept/50-partial/Partial_Ajax.xhtml to use this feature
-    // XXX todo: check full page transitions
-    class Overlay {
-        constructor(element, ajax = false, error = false, waitOverlayDelay) {
-            /**
-             * Is this overlay for an AJAX request, or an normal submit?
-             * We need this information, because AJAX need to clone the animated image, but for a normal submit
-             * we must not clone it, because the animation stops in some browsers.
-             */
-            this.ajax = true;
-            /**
-             * This boolean indicates, if the overlay is "error" or "wait".
-             */
-            this.error = false;
-            /**
-             * The delay for the wait overlay. If not set the default delay is read from Tobago.Config.
-             */
-            this.waitOverlayDelay = 0;
-            this.element = element;
-            this.ajax = ajax;
-            this.error = error;
-            this.waitOverlayDelay = waitOverlayDelay
-                ? waitOverlayDelay
-                : Config.get(this.ajax ? "Ajax.waitOverlayDelay" : "Tobago.waitOverlayDelay");
-            // create the overlay
-            this.overlay = document.createElement("div");
-            this.overlay.classList.add("tobago-page-overlay");
-            this.overlay.classList.add(this.error ? "tobago-page-overlay-markup-error" : null);
-            let left = "0";
-            let top = "0";
-            if (this.element.matches("body")) {
-                this.overlay.style.position = "fixed";
-                this.overlay.style.zIndex = "1500"; // greater than the bootstrap navbar
-            }
-            else {
-                const rect = this.element.getBoundingClientRect();
-                left = (rect.left + document.body.scrollLeft) + "px";
-                top = (rect.top + document.body.scrollTop) + "px";
-                this.overlay.style.width = this.element.offsetWidth + "px";
-                this.overlay.style.height = this.element.offsetHeight + "px";
-                // tbd: is this still needed?       this.overlay.style.position= "absolute"
-                // XXX is set via class, but seams to be overridden in IE11?
-            }
-            document.getElementsByTagName("body")[0].append(this.overlay);
-            let wait = document.createElement("div");
-            wait.classList.add("tobago-page-overlayCenter");
-            this.overlay.append(wait);
-            let image = document.createElement("i");
-            if (this.error) {
-                image.classList.add("fa", "fa-flash", "fa-3x");
-                wait.classList.add("alert-danger");
-            }
-            else {
-                image.classList.add("fa", "fa-refresh", "fa-3x", "fa-spin");
-                image.style.opacity = "0.4";
-            }
-            wait.append(image);
-            wait.style.display = ""; //XXX ?
-            this.overlay.style.backgroundColor = Page.page(this.element).style.backgroundColor;
-            this.overlay.style.left = left;
-            this.overlay.style.top = top;
-            setTimeout(() => {
-                this.overlay.classList.add("tobago-page-overlay-timeout");
-            }, this.waitOverlayDelay);
-            Overlay.overlayMap.set(element.id, this);
-            console.debug("----> set overlay " + element.id);
-        }
-        static destroy(id) {
-            console.debug("----> get overlay " + id);
-            const overlay = Overlay.overlayMap.get(id);
-            if (overlay) {
-                overlay.overlay.remove();
-                Overlay.overlayMap.delete(id);
-            }
-            else {
-                console.warn("Overlay not found for id='" + id + "'");
-            }
-        }
+    );
+  }
+
+  function getTrueOffsetParent(element) {
+    if (!isHTMLElement(element) || // https://github.com/popperjs/popper-core/issues/837
+    getComputedStyle$1(element).position === 'fixed') {
+      return null;
     }
-    Overlay.overlayMap = new Map();
-    Config.set("Tobago.waitOverlayDelay", 1000);
-    Config.set("Ajax.waitOverlayDelay", 1000);
-
-    var top = 'top';
-    var bottom = 'bottom';
-    var right = 'right';
-    var left = 'left';
-    var auto = 'auto';
-    var basePlacements = [top, bottom, right, left];
-    var start = 'start';
-    var end = 'end';
-    var clippingParents = 'clippingParents';
-    var viewport = 'viewport';
-    var popper = 'popper';
-    var reference = 'reference';
-    var variationPlacements = /*#__PURE__*/basePlacements.reduce(function (acc, placement) {
-      return acc.concat([placement + "-" + start, placement + "-" + end]);
-    }, []);
-    var placements = /*#__PURE__*/[].concat(basePlacements, [auto]).reduce(function (acc, placement) {
-      return acc.concat([placement, placement + "-" + start, placement + "-" + end]);
-    }, []); // modifiers that need to read the DOM
 
-    var beforeRead = 'beforeRead';
-    var read = 'read';
-    var afterRead = 'afterRead'; // pure-logic modifiers
+    return element.offsetParent;
+  } // `.offsetParent` reports `null` for fixed elements, while absolute elements
+  // return the containing block
 
-    var beforeMain = 'beforeMain';
-    var main = 'main';
-    var afterMain = 'afterMain'; // modifier with the purpose to write to the DOM (or write into a framework state)
 
-    var beforeWrite = 'beforeWrite';
-    var write = 'write';
-    var afterWrite = 'afterWrite';
-    var modifierPhases = [beforeRead, read, afterRead, beforeMain, main, afterMain, beforeWrite, write, afterWrite];
+  function getContainingBlock(element) {
+    var isFirefox = navigator.userAgent.toLowerCase().includes('firefox');
+    var currentNode = getParentNode(element);
 
-    function getNodeName(element) {
-      return element ? (element.nodeName || '').toLowerCase() : null;
+    while (isHTMLElement(currentNode) && ['html', 'body'].indexOf(getNodeName(currentNode)) < 0) {
+      var css = getComputedStyle$1(currentNode); // This is non-exhaustive but covers the most common CSS properties that
+      // create a containing block.
+      // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block
+
+      if (css.transform !== 'none' || css.perspective !== 'none' || css.contain === 'paint' || ['transform', 'perspective'].includes(css.willChange) || isFirefox && css.willChange === 'filter' || isFirefox && css.filter && css.filter !== 'none') {
+        return currentNode;
+      } else {
+        currentNode = currentNode.parentNode;
+      }
     }
 
-    /*:: import type { Window } from '../types'; */
+    return null;
+  } // Gets the closest ancestor positioned element. Handles some edge cases,
+  // such as table ancestors and cross browser bugs.
 
-    /*:: declare function getWindow(node: Node | Window): Window; */
-    function getWindow(node) {
-      if (node.toString() !== '[object Window]') {
-        var ownerDocument = node.ownerDocument;
-        return ownerDocument ? ownerDocument.defaultView || window : window;
-      }
 
-      return node;
-    }
+  function getOffsetParent(element) {
+    var window = getWindow(element);
+    var offsetParent = getTrueOffsetParent(element);
 
-    /*:: declare function isElement(node: mixed): boolean %checks(node instanceof
-      Element); */
+    while (offsetParent && isTableElement(offsetParent) && getComputedStyle$1(offsetParent).position === 'static') {
+      offsetParent = getTrueOffsetParent(offsetParent);
+    }
 
-    function isElement(node) {
-      var OwnElement = getWindow(node).Element;
-      return node instanceof OwnElement || node instanceof Element;
+    if (offsetParent && (getNodeName(offsetParent) === 'html' || getNodeName(offsetParent) === 'body' && getComputedStyle$1(offsetParent).position === 'static')) {
+      return window;
     }
-    /*:: declare function isHTMLElement(node: mixed): boolean %checks(node instanceof
-      HTMLElement); */
 
+    return offsetParent || getContainingBlock(element) || window;
+  }
 
-    function isHTMLElement(node) {
-      var OwnElement = getWindow(node).HTMLElement;
-      return node instanceof OwnElement || node instanceof HTMLElement;
-    }
-    /*:: declare function isShadowRoot(node: mixed): boolean %checks(node instanceof
-      ShadowRoot); */
+  function getMainAxisFromPlacement(placement) {
+    return ['top', 'bottom'].indexOf(placement) >= 0 ? 'x' : 'y';
+  }
 
+  var max = Math.max;
+  var min = Math.min;
+  var round = Math.round;
 
-    function isShadowRoot(node) {
-      // IE 11 has no ShadowRoot
-      if (typeof ShadowRoot === 'undefined') {
-        return false;
-      }
+  function within(min$1, value, max$1) {
+    return max(min$1, min(value, max$1));
+  }
 
-      var OwnElement = getWindow(node).ShadowRoot;
-      return node instanceof OwnElement || node instanceof ShadowRoot;
+  function getFreshSideObject() {
+    return {
+      top: 0,
+      right: 0,
+      bottom: 0,
+      left: 0
+    };
+  }
+
+  function mergePaddingObject(paddingObject) {
+    return Object.assign({}, getFreshSideObject(), paddingObject);
+  }
+
+  function expandToHashMap(value, keys) {
+    return keys.reduce(function (hashMap, key) {
+      hashMap[key] = value;
+      return hashMap;
+    }, {});
+  }
+
+  function arrow(_ref) {
+    var _state$modifiersData$;
+
+    var state = _ref.state,
+        name = _ref.name;
+    var arrowElement = state.elements.arrow;
+    var popperOffsets = state.modifiersData.popperOffsets;
+    var basePlacement = getBasePlacement(state.placement);
+    var axis = getMainAxisFromPlacement(basePlacement);
+    var isVertical = [left, right].indexOf(basePlacement) >= 0;
+    var len = isVertical ? 'height' : 'width';
+
+    if (!arrowElement || !popperOffsets) {
+      return;
+    }
+
+    var paddingObject = state.modifiersData[name + "#persistent"].padding;
+    var arrowRect = getLayoutRect(arrowElement);
+    var minProp = axis === 'y' ? top : left;
+    var maxProp = axis === 'y' ? bottom : right;
+    var endDiff = state.rects.reference[len] + state.rects.reference[axis] - popperOffsets[axis] - state.rects.popper[len];
+    var startDiff = popperOffsets[axis] - state.rects.reference[axis];
+    var arrowOffsetParent = getOffsetParent(arrowElement);
+    var clientSize = arrowOffsetParent ? axis === 'y' ? arrowOffsetParent.clientHeight || 0 : arrowOffsetParent.clientWidth || 0 : 0;
+    var centerToReference = endDiff / 2 - startDiff / 2; // Make sure the arrow doesn't overflow the popper if the center point is
+    // outside of the popper bounds
+
+    var min = paddingObject[minProp];
+    var max = clientSize - arrowRect[len] - paddingObject[maxProp];
+    var center = clientSize / 2 - arrowRect[len] / 2 + centerToReference;
+    var offset = within(min, center, max); // Prevents breaking syntax highlighting...
+
+    var axisProp = axis;
+    state.modifiersData[name] = (_state$modifiersData$ = {}, _state$modifiersData$[axisProp] = offset, _state$modifiersData$.centerOffset = offset - center, _state$modifiersData$);
+  }
+
+  function effect$1(_ref2) {
+    var state = _ref2.state,
+        options = _ref2.options,
+        name = _ref2.name;
+    var _options$element = options.element,
+        arrowElement = _options$element === void 0 ? '[data-popper-arrow]' : _options$element,
+        _options$padding = options.padding,
+        padding = _options$padding === void 0 ? 0 : _options$padding;
+
+    if (arrowElement == null) {
+      return;
+    } // CSS selector
+
+
+    if (typeof arrowElement === 'string') {
+      arrowElement = state.elements.popper.querySelector(arrowElement);
+
+      if (!arrowElement) {
+        return;
+      }
     }
 
-    // and applies them to the HTMLElements such as popper and arrow
+    if (!contains(state.elements.popper, arrowElement)) {
 
-    function applyStyles(_ref) {
-      var state = _ref.state;
-      Object.keys(state.elements).forEach(function (name) {
-        var style = state.styles[name] || {};
-        var attributes = state.attributes[name] || {};
-        var element = state.elements[name]; // arrow is optional + virtual elements
+      return;
+    }
 
-        if (!isHTMLElement(element) || !getNodeName(element)) {
-          return;
-        } // Flow doesn't support to extend this property, but it's the most
-        // effective way to apply styles to an HTMLElement
-        // $FlowFixMe[cannot-write]
+    padding = typeof padding === 'function' ? padding(Object.assign({}, state.rects, {
+      placement: state.placement
+    })) : padding;
+    state.elements.arrow = arrowElement;
+    state.modifiersData[name + "#persistent"] = {
+      padding: mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements))
+    };
+  } // eslint-disable-next-line import/no-unused-modules
+
+
+  var arrow$1 = {
+    name: 'arrow',
+    enabled: true,
+    phase: 'main',
+    fn: arrow,
+    effect: effect$1,
+    requires: ['popperOffsets'],
+    requiresIfExists: ['preventOverflow']
+  };
+
+  var unsetSides = {
+    top: 'auto',
+    right: 'auto',
+    bottom: 'auto',
+    left: 'auto'
+  }; // Round the offsets to the nearest suitable subpixel based on the DPR.
+  // Zooming can change the DPR, but it seems to report a value that will
+  // cleanly divide the values into the appropriate subpixels.
+
+  function roundOffsetsByDPR(_ref) {
+    var x = _ref.x,
+        y = _ref.y;
+    var win = window;
+    var dpr = win.devicePixelRatio || 1;
+    return {
+      x: round(round(x * dpr) / dpr) || 0,
+      y: round(round(y * dpr) / dpr) || 0
+    };
+  }
 
+  function mapToStyles(_ref2) {
+    var _Object$assign2;
 
-        Object.assign(element.style, style);
-        Object.keys(attributes).forEach(function (name) {
-          var value = attributes[name];
+    var popper = _ref2.popper,
+        popperRect = _ref2.popperRect,
+        placement = _ref2.placement,
+        offsets = _ref2.offsets,
+        position = _ref2.position,
+        gpuAcceleration = _ref2.gpuAcceleration,
+        adaptive = _ref2.adaptive,
+        roundOffsets = _ref2.roundOffsets;
 
-          if (value === false) {
-            element.removeAttribute(name);
-          } else {
-            element.setAttribute(name, value === true ? '' : value);
-          }
-        });
-      });
-    }
+    var _ref3 = roundOffsets === true ? roundOffsetsByDPR(offsets) : typeof roundOffsets === 'function' ? roundOffsets(offsets) : offsets,
+        _ref3$x = _ref3.x,
+        x = _ref3$x === void 0 ? 0 : _ref3$x,
+        _ref3$y = _ref3.y,
+        y = _ref3$y === void 0 ? 0 : _ref3$y;
 
-    function effect(_ref2) {
-      var state = _ref2.state;
-      var initialStyles = {
-        popper: {
-          position: state.options.strategy,
-          left: '0',
-          top: '0',
-          margin: '0'
-        },
-        arrow: {
-          position: 'absolute'
-        },
-        reference: {}
-      };
-      Object.assign(state.elements.popper.style, initialStyles.popper);
-      state.styles = initialStyles;
+    var hasX = offsets.hasOwnProperty('x');
+    var hasY = offsets.hasOwnProperty('y');
+    var sideX = left;
+    var sideY = top;
+    var win = window;
 
-      if (state.elements.arrow) {
-        Object.assign(state.elements.arrow.style, initialStyles.arrow);
-      }
+    if (adaptive) {
+      var offsetParent = getOffsetParent(popper);
+      var heightProp = 'clientHeight';
+      var widthProp = 'clientWidth';
 
-      return function () {
-        Object.keys(state.elements).forEach(function (name) {
-          var element = state.elements[name];
-          var attributes = state.attributes[name] || {};
-          var styleProperties = Object.keys(state.styles.hasOwnProperty(name) ? state.styles[name] : initialStyles[name]); // Set all values to an empty string to unset them
+      if (offsetParent === getWindow(popper)) {
+        offsetParent = getDocumentElement(popper);
 
-          var style = styleProperties.reduce(function (style, property) {
-            style[property] = '';
-            return style;
-          }, {}); // arrow is optional + virtual elements
+        if (getComputedStyle$1(offsetParent).position !== 'static') {
+          heightProp = 'scrollHeight';
+          widthProp = 'scrollWidth';
+        }
+      } // $FlowFixMe[incompatible-cast]: force type refinement, we compare offsetParent with window above, but Flow doesn't detect it
 
-          if (!isHTMLElement(element) || !getNodeName(element)) {
-            return;
-          }
+      /*:: offsetParent = (offsetParent: Element); */
 
-          Object.assign(element.style, style);
-          Object.keys(attributes).forEach(function (attribute) {
-            element.removeAttribute(attribute);
-          });
-        });
-      };
-    } // eslint-disable-next-line import/no-unused-modules
 
+      if (placement === top) {
+        sideY = bottom; // $FlowFixMe[prop-missing]
 
-    var applyStyles$1 = {
-      name: 'applyStyles',
-      enabled: true,
-      phase: 'write',
-      fn: applyStyles,
-      effect: effect,
-      requires: ['computeStyles']
-    };
+        y -= offsetParent[heightProp] - popperRect.height;
+        y *= gpuAcceleration ? 1 : -1;
+      }
 
-    function getBasePlacement(placement) {
-      return placement.split('-')[0];
-    }
+      if (placement === left) {
+        sideX = right; // $FlowFixMe[prop-missing]
 
-    // Returns the layout rect of an element relative to its offsetParent. Layout
-    // means it doesn't take into account transforms.
-    function getLayoutRect(element) {
-      return {
-        x: element.offsetLeft,
-        y: element.offsetTop,
-        width: element.offsetWidth,
-        height: element.offsetHeight
-      };
+        x -= offsetParent[widthProp] - popperRect.width;
+        x *= gpuAcceleration ? 1 : -1;
+      }
     }
 
-    function contains(parent, child) {
-      var rootNode = child.getRootNode && child.getRootNode(); // First, attempt with faster native method
+    var commonStyles = Object.assign({
+      position: position
+    }, adaptive && unsetSides);
 
-      if (parent.contains(child)) {
-        return true;
-      } // then fallback to custom implementation with Shadow DOM support
-      else if (rootNode && isShadowRoot(rootNode)) {
-          var next = child;
+    if (gpuAcceleration) {
+      var _Object$assign;
 
-          do {
-            if (next && parent.isSameNode(next)) {
-              return true;
-            } // $FlowFixMe[prop-missing]: need a better way to handle this...
+      return Object.assign({}, commonStyles, (_Object$assign = {}, _Object$assign[sideY] = hasY ? '0' : '', _Object$assign[sideX] = hasX ? '0' : '', _Object$assign.transform = (win.devicePixelRatio || 1) < 2 ? "translate(" + x + "px, " + y + "px)" : "translate3d(" + x + "px, " + y + "px, 0)", _Object$assign));
+    }
 
+    return Object.assign({}, commonStyles, (_Object$assign2 = {}, _Object$assign2[sideY] = hasY ? y + "px" : '', _Object$assign2[sideX] = hasX ? x + "px" : '', _Object$assign2.transform = '', _Object$assign2));
+  }
 
-            next = next.parentNode || next.host;
-          } while (next);
-        } // Give up, the result is false
+  function computeStyles(_ref4) {
+    var state = _ref4.state,
+        options = _ref4.options;
+    var _options$gpuAccelerat = options.gpuAcceleration,
+        gpuAcceleration = _options$gpuAccelerat === void 0 ? true : _options$gpuAccelerat,
+        _options$adaptive = options.adaptive,
+        adaptive = _options$adaptive === void 0 ? true : _options$adaptive,
+        _options$roundOffsets = options.roundOffsets,
+        roundOffsets = _options$roundOffsets === void 0 ? true : _options$roundOffsets;
 
+    var commonStyles = {
+      placement: getBasePlacement(state.placement),
+      popper: state.elements.popper,
+      popperRect: state.rects.popper,
+      gpuAcceleration: gpuAcceleration
+    };
 
-      return false;
+    if (state.modifiersData.popperOffsets != null) {
+      state.styles.popper = Object.assign({}, state.styles.popper, mapToStyles(Object.assign({}, commonStyles, {
+        offsets: state.modifiersData.popperOffsets,
+        position: state.options.strategy,
+        adaptive: adaptive,
+        roundOffsets: roundOffsets
+      })));
     }
 
-    function getComputedStyle$1(element) {
-      return getWindow(element).getComputedStyle(element);
+    if (state.modifiersData.arrow != null) {
+      state.styles.arrow = Object.assign({}, state.styles.arrow, mapToStyles(Object.assign({}, commonStyles, {
+        offsets: state.modifiersData.arrow,
+        position: 'absolute',
+        adaptive: false,
+        roundOffsets: roundOffsets
+      })));
     }
 
-    function isTableElement(element) {
-      return ['table', 'td', 'th'].indexOf(getNodeName(element)) >= 0;
+    state.attributes.popper = Object.assign({}, state.attributes.popper, {
+      'data-popper-placement': state.placement
+    });
+  } // eslint-disable-next-line import/no-unused-modules
+
+
+  var computeStyles$1 = {
+    name: 'computeStyles',
+    enabled: true,
+    phase: 'beforeWrite',
+    fn: computeStyles,
+    data: {}
+  };
+
+  var passive = {
+    passive: true
+  };
+
+  function effect$2(_ref) {
+    var state = _ref.state,
+        instance = _ref.instance,
+        options = _ref.options;
+    var _options$scroll = options.scroll,
+        scroll = _options$scroll === void 0 ? true : _options$scroll,
+        _options$resize = options.resize,
+        resize = _options$resize === void 0 ? true : _options$resize;
+    var window = getWindow(state.elements.popper);
+    var scrollParents = [].concat(state.scrollParents.reference, state.scrollParents.popper);
+
+    if (scroll) {
+      scrollParents.forEach(function (scrollParent) {
+        scrollParent.addEventListener('scroll', instance.update, passive);
+      });
     }
 
-    function getDocumentElement(element) {
-      // $FlowFixMe[incompatible-return]: assume body is always available
-      return ((isElement(element) ? element.ownerDocument : // $FlowFixMe[prop-missing]
-      element.document) || window.document).documentElement;
+    if (resize) {
+      window.addEventListener('resize', instance.update, passive);
     }
 
-    function getParentNode(element) {
-      if (getNodeName(element) === 'html') {
-        return element;
+    return function () {
+      if (scroll) {
+        scrollParents.forEach(function (scrollParent) {
+          scrollParent.removeEventListener('scroll', instance.update, passive);
+        });
       }
 
-      return (// this is a quicker (but less type safe) way to save quite some bytes from the bundle
-        // $FlowFixMe[incompatible-return]
-        // $FlowFixMe[prop-missing]
-        element.assignedSlot || // step into the shadow DOM of the parent of a slotted node
-        element.parentNode || ( // DOM Element detected
-        isShadowRoot(element) ? element.host : null) || // ShadowRoot detected
-        // $FlowFixMe[incompatible-call]: HTMLElement is a Node
-        getDocumentElement(element) // fallback
-
-      );
-    }
-
-    function getTrueOffsetParent(element) {
-      if (!isHTMLElement(element) || // https://github.com/popperjs/popper-core/issues/837
-      getComputedStyle$1(element).position === 'fixed') {
-        return null;
+      if (resize) {
+        window.removeEventListener('resize', instance.update, passive);
       }
+    };
+  } // eslint-disable-next-line import/no-unused-modules
+
+
+  var eventListeners = {
+    name: 'eventListeners',
+    enabled: true,
+    phase: 'write',
+    fn: function fn() {},
+    effect: effect$2,
+    data: {}
+  };
+
+  var hash = {
+    left: 'right',
+    right: 'left',
+    bottom: 'top',
+    top: 'bottom'
+  };
+  function getOppositePlacement(placement) {
+    return placement.replace(/left|right|bottom|top/g, function (matched) {
+      return hash[matched];
+    });
+  }
+
+  var hash$1 = {
+    start: 'end',
+    end: 'start'
+  };
+  function getOppositeVariationPlacement(placement) {
+    return placement.replace(/start|end/g, function (matched) {
+      return hash$1[matched];
+    });
+  }
+
+  function getBoundingClientRect(element) {
+    var rect = element.getBoundingClientRect();
+    return {
+      width: rect.width,
+      height: rect.height,
+      top: rect.top,
+      right: rect.right,
+      bottom: rect.bottom,
+      left: rect.left,
+      x: rect.left,
+      y: rect.top
+    };
+  }
+
+  function getWindowScroll(node) {
+    var win = getWindow(node);
+    var scrollLeft = win.pageXOffset;
+    var scrollTop = win.pageYOffset;
+    return {
+      scrollLeft: scrollLeft,
+      scrollTop: scrollTop
+    };
+  }
+
+  function getWindowScrollBarX(element) {
+    // If <html> has a CSS width greater than the viewport, then this will be
+    // incorrect for RTL.
+    // Popper 1 is broken in this case and never had a bug report so let's assume
+    // it's not an issue. I don't think anyone ever specifies width on <html>
+    // anyway.
+    // Browsers where the left scrollbar doesn't cause an issue report `0` for
+    // this (e.g. Edge 2019, IE11, Safari)
+    return getBoundingClientRect(getDocumentElement(element)).left + getWindowScroll(element).scrollLeft;
+  }
+
+  function getViewportRect(element) {
+    var win = getWindow(element);
+    var html = getDocumentElement(element);
+    var visualViewport = win.visualViewport;
+    var width = html.clientWidth;
+    var height = html.clientHeight;
+    var x = 0;
+    var y = 0; // NB: This isn't supported on iOS <= 12. If the keyboard is open, the popper
+    // can be obscured underneath it.
+    // Also, `html.clientHeight` adds the bottom bar height in Safari iOS, even
+    // if it isn't open, so if this isn't available, the popper will be detected
+    // to overflow the bottom of the screen too early.
+
+    if (visualViewport) {
+      width = visualViewport.width;
+      height = visualViewport.height; // Uses Layout Viewport (like Chrome; Safari does not currently)
+      // In Chrome, it returns a value very close to 0 (+/-) but contains rounding
+      // errors due to floating point numbers, so we need to check precision.
+      // Safari returns a number <= 0, usually < -1 when pinch-zoomed
+      // Feature detection fails in mobile emulation mode in Chrome.
+      // Math.abs(win.innerWidth / visualViewport.scale - visualViewport.width) <
+      // 0.001
+      // Fallback here: "Not Safari" userAgent
+
+      if (!/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) {
+        x = visualViewport.offsetLeft;
+        y = visualViewport.offsetTop;
+      }
+    }
+
+    return {
+      width: width,
+      height: height,
+      x: x + getWindowScrollBarX(element),
+      y: y
+    };
+  }
 
-      return element.offsetParent;
-    } // `.offsetParent` reports `null` for fixed elements, while absolute elements
-    // return the containing block
-
-
-    function getContainingBlock(element) {
-      var isFirefox = navigator.userAgent.toLowerCase().includes('firefox');
-      var currentNode = getParentNode(element);
-
-      while (isHTMLElement(currentNode) && ['html', 'body'].indexOf(getNodeName(currentNode)) < 0) {
-        var css = getComputedStyle$1(currentNode); // This is non-exhaustive but covers the most common CSS properties that
-        // create a containing block.
-        // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block
+  // of the `<html>` and `<body>` rect bounds if horizontally scrollable
 
-        if (css.transform !== 'none' || css.perspective !== 'none' || css.contain === 'paint' || ['transform', 'perspective'].includes(css.willChange) || isFirefox && css.willChange === 'filter' || isFirefox && css.filter && css.filter !== 'none') {
-          return currentNode;
-        } else {
-          currentNode = currentNode.parentNode;
-        }
-      }
+  function getDocumentRect(element) {
+    var _element$ownerDocumen;
 
-      return null;
-    } // Gets the closest ancestor positioned element. Handles some edge cases,
-    // such as table ancestors and cross browser bugs.
+    var html = getDocumentElement(element);
+    var winScroll = getWindowScroll(element);
+    var body = (_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body;
+    var width = max(html.scrollWidth, html.clientWidth, body ? body.scrollWidth : 0, body ? body.clientWidth : 0);
+    var height = max(html.scrollHeight, html.clientHeight, body ? body.scrollHeight : 0, body ? body.clientHeight : 0);
+    var x = -winScroll.scrollLeft + getWindowScrollBarX(element);
+    var y = -winScroll.scrollTop;
 
+    if (getComputedStyle$1(body || html).direction === 'rtl') {
+      x += max(html.clientWidth, body ? body.clientWidth : 0) - width;
+    }
 
-    function getOffsetParent(element) {
-      var window = getWindow(element);
-      var offsetParent = getTrueOffsetParent(element);
+    return {
+      width: width,
+      height: height,
+      x: x,
+      y: y
+    };
+  }
 
-      while (offsetParent && isTableElement(offsetParent) && getComputedStyle$1(offsetParent).position === 'static') {
-        offsetParent = getTrueOffsetParent(offsetParent);
-      }
+  function isScrollParent(element) {
+    // Firefox wants us to check `-x` and `-y` variations as well
+    var _getComputedStyle = getComputedStyle$1(element),
+        overflow = _getComputedStyle.overflow,
+        overflowX = _getComputedStyle.overflowX,
+        overflowY = _getComputedStyle.overflowY;
 
-      if (offsetParent && (getNodeName(offsetParent) === 'html' || getNodeName(offsetParent) === 'body' && getComputedStyle$1(offsetParent).position === 'static')) {
-        return window;
-      }
+    return /auto|scroll|overlay|hidden/.test(overflow + overflowY + overflowX);
+  }
 
-      return offsetParent || getContainingBlock(element) || window;
+  function getScrollParent(node) {
+    if (['html', 'body', '#document'].indexOf(getNodeName(node)) >= 0) {
+      // $FlowFixMe[incompatible-return]: assume body is always available
+      return node.ownerDocument.body;
     }
 
-    function getMainAxisFromPlacement(placement) {
-      return ['top', 'bottom'].indexOf(placement) >= 0 ? 'x' : 'y';
+    if (isHTMLElement(node) && isScrollParent(node)) {
+      return node;
     }
 
-    var max = Math.max;
-    var min = Math.min;
-    var round = Math.round;
+    return getScrollParent(getParentNode(node));
+  }
 
-    function within(min$1, value, max$1) {
-      return max(min$1, min(value, max$1));
-    }
+  /*
+  given a DOM element, return the list of all scroll parents, up the list of ancesors
+  until we get to the top window object. This list is what we attach scroll listeners
+  to, because if any of these parent elements scroll, we'll need to re-calculate the
+  reference element's position.
+  */
 
-    function getFreshSideObject() {
-      return {
-        top: 0,
-        right: 0,
-        bottom: 0,
-        left: 0
-      };
-    }
+  function listScrollParents(element, list) {
+    var _element$ownerDocumen;
 
-    function mergePaddingObject(paddingObject) {
-      return Object.assign({}, getFreshSideObject(), paddingObject);
+    if (list === void 0) {
+      list = [];
     }
 
-    function expandToHashMap(value, keys) {
-      return keys.reduce(function (hashMap, key) {
-        hashMap[key] = value;
-        return hashMap;
-      }, {});
-    }
+    var scrollParent = getScrollParent(element);
+    var isBody = scrollParent === ((_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body);
+    var win = getWindow(scrollParent);
+    var target = isBody ? [win].concat(win.visualViewport || [], isScrollParent(scrollParent) ? scrollParent : []) : scrollParent;
+    var updatedList = list.concat(target);
+    return isBody ? updatedList : // $FlowFixMe[incompatible-call]: isBody tells us target will be an HTMLElement here
+    updatedList.concat(listScrollParents(getParentNode(target)));
+  }
 
-    function arrow(_ref) {
-      var _state$modifiersData$;
+  function rectToClientRect(rect) {
+    return Object.assign({}, rect, {
+      left: rect.x,
+      top: rect.y,
+      right: rect.x + rect.width,
+      bottom: rect.y + rect.height
+    });
+  }
+
+  function getInnerBoundingClientRect(element) {
+    var rect = getBoundingClientRect(element);
+    rect.top = rect.top + element.clientTop;
+    rect.left = rect.left + element.clientLeft;
+    rect.bottom = rect.top + element.clientHeight;
+    rect.right = rect.left + element.clientWidth;
+    rect.width = element.clientWidth;
+    rect.height = element.clientHeight;
+    rect.x = rect.left;
+    rect.y = rect.top;
+    return rect;
+  }
+
+  function getClientRectFromMixedType(element, clippingParent) {
+    return clippingParent === viewport ? rectToClientRect(getViewportRect(element)) : isHTMLElement(clippingParent) ? getInnerBoundingClientRect(clippingParent) : rectToClientRect(getDocumentRect(getDocumentElement(element)));
+  } // A "clipping parent" is an overflowable container with the characteristic of
+  // clipping (or hiding) overflowing elements with a position different from
+  // `initial`
+
+
+  function getClippingParents(element) {
+    var clippingParents = listScrollParents(getParentNode(element));
+    var canEscapeClipping = ['absolute', 'fixed'].indexOf(getComputedStyle$1(element).position) >= 0;
+    var clipperElement = canEscapeClipping && isHTMLElement(element) ? getOffsetParent(element) : element;
+
+    if (!isElement(clipperElement)) {
+      return [];
+    } // $FlowFixMe[incompatible-return]: https://github.com/facebook/flow/issues/1414
+
+
+    return clippingParents.filter(function (clippingParent) {
+      return isElement(clippingParent) && contains(clippingParent, clipperElement) && getNodeName(clippingParent) !== 'body';
+    });
+  } // Gets the maximum area that the element is visible in due to any number of
+  // clipping parents
+
+
+  function getClippingRect(element, boundary, rootBoundary) {
+    var mainClippingParents = boundary === 'clippingParents' ? getClippingParents(element) : [].concat(boundary);
+    var clippingParents = [].concat(mainClippingParents, [rootBoundary]);
+    var firstClippingParent = clippingParents[0];
+    var clippingRect = clippingParents.reduce(function (accRect, clippingParent) {
+      var rect = getClientRectFromMixedType(element, clippingParent);
+      accRect.top = max(rect.top, accRect.top);
+      accRect.right = min(rect.right, accRect.right);
+      accRect.bottom = min(rect.bottom, accRect.bottom);
+      accRect.left = max(rect.left, accRect.left);
+      return accRect;
+    }, getClientRectFromMixedType(element, firstClippingParent));
+    clippingRect.width = clippingRect.right - clippingRect.left;
+    clippingRect.height = clippingRect.bottom - clippingRect.top;
+    clippingRect.x = clippingRect.left;
+    clippingRect.y = clippingRect.top;
+    return clippingRect;
+  }
+
+  function getVariation(placement) {
+    return placement.split('-')[1];
+  }
+
+  function computeOffsets(_ref) {
+    var reference = _ref.reference,
+        element = _ref.element,
+        placement = _ref.placement;
+    var basePlacement = placement ? getBasePlacement(placement) : null;
+    var variation = placement ? getVariation(placement) : null;
+    var commonX = reference.x + reference.width / 2 - element.width / 2;
+    var commonY = reference.y + reference.height / 2 - element.height / 2;
+    var offsets;
+
+    switch (basePlacement) {
+      case top:
+        offsets = {
+          x: commonX,
+          y: reference.y - element.height
+        };
+        break;
 
-      var state = _ref.state,
-          name = _ref.name;
-      var arrowElement = state.elements.arrow;
-      var popperOffsets = state.modifiersData.popperOffsets;
-      var basePlacement = getBasePlacement(state.placement);
-      var axis = getMainAxisFromPlacement(basePlacement);
-      var isVertical = [left, right].indexOf(basePlacement) >= 0;
-      var len = isVertical ? 'height' : 'width';
+      case bottom:
+        offsets = {
+          x: commonX,
+          y: reference.y + reference.height
+        };
+        break;
 
-      if (!arrowElement || !popperOffsets) {
-        return;
-      }
+      case right:
+        offsets = {
+          x: reference.x + reference.width,
+          y: commonY
+        };
+        break;
 
-      var paddingObject = state.modifiersData[name + "#persistent"].padding;
-      var arrowRect = getLayoutRect(arrowElement);
-      var minProp = axis === 'y' ? top : left;
-      var maxProp = axis === 'y' ? bottom : right;
-      var endDiff = state.rects.reference[len] + state.rects.reference[axis] - popperOffsets[axis] - state.rects.popper[len];
-      var startDiff = popperOffsets[axis] - state.rects.reference[axis];
-      var arrowOffsetParent = getOffsetParent(arrowElement);
-      var clientSize = arrowOffsetParent ? axis === 'y' ? arrowOffsetParent.clientHeight || 0 : arrowOffsetParent.clientWidth || 0 : 0;
-      var centerToReference = endDiff / 2 - startDiff / 2; // Make sure the arrow doesn't overflow the popper if the center point is
-      // outside of the popper bounds
-
-      var min = paddingObject[minProp];
-      var max = clientSize - arrowRect[len] - paddingObject[maxProp];
-      var center = clientSize / 2 - arrowRect[len] / 2 + centerToReference;
-      var offset = within(min, center, max); // Prevents breaking syntax highlighting...
-
-      var axisProp = axis;
-      state.modifiersData[name] = (_state$modifiersData$ = {}, _state$modifiersData$[axisProp] = offset, _state$modifiersData$.centerOffset = offset - center, _state$modifiersData$);
-    }
-
-    function effect$1(_ref2) {
-      var state = _ref2.state,
-          options = _ref2.options,
-          name = _ref2.name;
-      var _options$element = options.element,
-          arrowElement = _options$element === void 0 ? '[data-popper-arrow]' : _options$element,
-          _options$padding = options.padding,
-          padding = _options$padding === void 0 ? 0 : _options$padding;
-
-      if (arrowElement == null) {
-        return;
-      } // CSS selector
+      case left:
+        offsets = {
+          x: reference.x - element.width,
+          y: commonY
+        };
+        break;
 
+      default:
+        offsets = {
+          x: reference.x,
+          y: reference.y
+        };
+    }
 
-      if (typeof arrowElement === 'string') {
-        arrowElement = state.elements.popper.querySelector(arrowElement);
+    var mainAxis = basePlacement ? getMainAxisFromPlacement(basePlacement) : null;
 
-        if (!arrowElement) {
-          return;
-        }
-      }
+    if (mainAxis != null) {
+      var len = mainAxis === 'y' ? 'height' : 'width';
 
-      if (!contains(state.elements.popper, arrowElement)) {
+      switch (variation) {
+        case start:
+          offsets[mainAxis] = offsets[mainAxis] - (reference[len] / 2 - element[len] / 2);
+          break;
 
-        return;
+        case end:
+          offsets[mainAxis] = offsets[mainAxis] + (reference[len] / 2 - element[len] / 2);
+          break;
       }
+    }
 
-      padding = typeof padding === 'function' ? padding(Object.assign({}, state.rects, {
-        placement: state.placement
-      })) : padding;
-      state.elements.arrow = arrowElement;
-      state.modifiersData[name + "#persistent"] = {
-        padding: mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements))
-      };
-    } // eslint-disable-next-line import/no-unused-modules
-
-
-    var arrow$1 = {
-      name: 'arrow',
-      enabled: true,
-      phase: 'main',
-      fn: arrow,
-      effect: effect$1,
-      requires: ['popperOffsets'],
-      requiresIfExists: ['preventOverflow']
-    };
-
-    var unsetSides = {
-      top: 'auto',
-      right: 'auto',
-      bottom: 'auto',
-      left: 'auto'
-    }; // Round the offsets to the nearest suitable subpixel based on the DPR.
-    // Zooming can change the DPR, but it seems to report a value that will
-    // cleanly divide the values into the appropriate subpixels.
-
-    function roundOffsetsByDPR(_ref) {
-      var x = _ref.x,
-          y = _ref.y;
-      var win = window;
-      var dpr = win.devicePixelRatio || 1;
-      return {
-        x: round(round(x * dpr) / dpr) || 0,
-        y: round(round(y * dpr) / dpr) || 0
-      };
+    return offsets;
+  }
+
+  function detectOverflow(state, options) {
+    if (options === void 0) {
+      options = {};
+    }
+
+    var _options = options,
+        _options$placement = _options.placement,
+        placement = _options$placement === void 0 ? state.placement : _options$placement,
+        _options$boundary = _options.boundary,
+        boundary = _options$boundary === void 0 ? clippingParents : _options$boundary,
+        _options$rootBoundary = _options.rootBoundary,
+        rootBoundary = _options$rootBoundary === void 0 ? viewport : _options$rootBoundary,
+        _options$elementConte = _options.elementContext,
+        elementContext = _options$elementConte === void 0 ? popper : _options$elementConte,
+        _options$altBoundary = _options.altBoundary,
+        altBoundary = _options$altBoundary === void 0 ? false : _options$altBoundary,
+        _options$padding = _options.padding,
+        padding = _options$padding === void 0 ? 0 : _options$padding;
+    var paddingObject = mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements));
+    var altContext = elementContext === popper ? reference : popper;
+    var referenceElement = state.elements.reference;
+    var popperRect = state.rects.popper;
+    var element = state.elements[altBoundary ? altContext : elementContext];
+    var clippingClientRect = getClippingRect(isElement(element) ? element : element.contextElement || getDocumentElement(state.elements.popper), boundary, rootBoundary);
+    var referenceClientRect = getBoundingClientRect(referenceElement);
+    var popperOffsets = computeOffsets({
+      reference: referenceClientRect,
+      element: popperRect,
+      strategy: 'absolute',
+      placement: placement
+    });
+    var popperClientRect = rectToClientRect(Object.assign({}, popperRect, popperOffsets));
+    var elementClientRect = elementContext === popper ? popperClientRect : referenceClientRect; // positive = overflowing the clipping rect
+    // 0 or negative = within the clipping rect
+
+    var overflowOffsets = {
+      top: clippingClientRect.top - elementClientRect.top + paddingObject.top,
+      bottom: elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom,
+      left: clippingClientRect.left - elementClientRect.left + paddingObject.left,
+      right: elementClientRect.right - clippingClientRect.right + paddingObject.right
+    };
+    var offsetData = state.modifiersData.offset; // Offsets can be applied only to the popper element
+
+    if (elementContext === popper && offsetData) {
+      var offset = offsetData[placement];
+      Object.keys(overflowOffsets).forEach(function (key) {
+        var multiply = [right, bottom].indexOf(key) >= 0 ? 1 : -1;
+        var axis = [top, bottom].indexOf(key) >= 0 ? 'y' : 'x';
+        overflowOffsets[key] += offset[axis] * multiply;
+      });
     }
 
-    function mapToStyles(_ref2) {
-      var _Object$assign2;
+    return overflowOffsets;
+  }
 
-      var popper = _ref2.popper,
-          popperRect = _ref2.popperRect,
-          placement = _ref2.placement,
-          offsets = _ref2.offsets,
-          position = _ref2.position,
-          gpuAcceleration = _ref2.gpuAcceleration,
-          adaptive = _ref2.adaptive,
-          roundOffsets = _ref2.roundOffsets;
+  /*:: type OverflowsMap = { [ComputedPlacement]: number }; */
 
-      var _ref3 = roundOffsets === true ? roundOffsetsByDPR(offsets) : typeof roundOffsets === 'function' ? roundOffsets(offsets) : offsets,
-          _ref3$x = _ref3.x,
-          x = _ref3$x === void 0 ? 0 : _ref3$x,
-          _ref3$y = _ref3.y,
-          y = _ref3$y === void 0 ? 0 : _ref3$y;
+  /*;; type OverflowsMap = { [key in ComputedPlacement]: number }; */
+  function computeAutoPlacement(state, options) {
+    if (options === void 0) {
+      options = {};
+    }
 
-      var hasX = offsets.hasOwnProperty('x');
-      var hasY = offsets.hasOwnProperty('y');
-      var sideX = left;
-      var sideY = top;
-      var win = window;
+    var _options = options,
+        placement = _options.placement,
+        boundary = _options.boundary,
+        rootBoundary = _options.rootBoundary,
+        padding = _options.padding,
+        flipVariations = _options.flipVariations,
+        _options$allowedAutoP = _options.allowedAutoPlacements,
+        allowedAutoPlacements = _options$allowedAutoP === void 0 ? placements : _options$allowedAutoP;
+    var variation = getVariation(placement);
+    var placements$1 = variation ? flipVariations ? variationPlacements : variationPlacements.filter(function (placement) {
+      return getVariation(placement) === variation;
+    }) : basePlacements;
+    var allowedPlacements = placements$1.filter(function (placement) {
+      return allowedAutoPlacements.indexOf(placement) >= 0;
+    });
 
-      if (adaptive) {
-        var offsetParent = getOffsetParent(popper);
-        var heightProp = 'clientHeight';
-        var widthProp = 'clientWidth';
+    if (allowedPlacements.length === 0) {
+      allowedPlacements = placements$1;
+    } // $FlowFixMe[incompatible-type]: Flow seems to have problems with two array unions...
 
-        if (offsetParent === getWindow(popper)) {
-          offsetParent = getDocumentElement(popper);
 
-          if (getComputedStyle$1(offsetParent).position !== 'static') {
-            heightProp = 'scrollHeight';
-            widthProp = 'scrollWidth';
-          }
-        } // $FlowFixMe[incompatible-cast]: force type refinement, we compare offsetParent with window above, but Flow doesn't detect it
+    var overflows = allowedPlacements.reduce(function (acc, placement) {
+      acc[placement] = detectOverflow(state, {
+        placement: placement,
+        boundary: boundary,
+        rootBoundary: rootBoundary,
+        padding: padding
+      })[getBasePlacement(placement)];
+      return acc;
+    }, {});
+    return Object.keys(overflows).sort(function (a, b) {
+      return overflows[a] - overflows[b];
+    });
+  }
+
+  function getExpandedFallbackPlacements(placement) {
+    if (getBasePlacement(placement) === auto) {
+      return [];
+    }
+
+    var oppositePlacement = getOppositePlacement(placement);
+    return [getOppositeVariationPlacement(placement), oppositePlacement, getOppositeVariationPlacement(oppositePlacement)];
+  }
+
+  function flip(_ref) {
+    var state = _ref.state,
+        options = _ref.options,
+        name = _ref.name;
+
+    if (state.modifiersData[name]._skip) {
+      return;
+    }
+
+    var _options$mainAxis = options.mainAxis,
+        checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis,
+        _options$altAxis = options.altAxis,
+        checkAltAxis = _options$altAxis === void 0 ? true : _options$altAxis,
+        specifiedFallbackPlacements = options.fallbackPlacements,
+        padding = options.padding,
+        boundary = options.boundary,
+        rootBoundary = options.rootBoundary,
+        altBoundary = options.altBoundary,
+        _options$flipVariatio = options.flipVariations,
+        flipVariations = _options$flipVariatio === void 0 ? true : _options$flipVariatio,
+        allowedAutoPlacements = options.allowedAutoPlacements;
+    var preferredPlacement = state.options.placement;
+    var basePlacement = getBasePlacement(preferredPlacement);
+    var isBasePlacement = basePlacement === preferredPlacement;
+    var fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipVariations ? [getOppositePlacement(preferredPlacement)] : getExpandedFallbackPlacements(preferredPlacement));
+    var placements = [preferredPlacement].concat(fallbackPlacements).reduce(function (acc, placement) {
+      return acc.concat(getBasePlacement(placement) === auto ? computeAutoPlacement(state, {
+        placement: placement,
+        boundary: boundary,
+        rootBoundary: rootBoundary,
+        padding: padding,
+        flipVariations: flipVariations,
+        allowedAutoPlacements: allowedAutoPlacements
+      }) : placement);
+    }, []);
+    var referenceRect = state.rects.reference;
+    var popperRect = state.rects.popper;
+    var checksMap = new Map();
+    var makeFallbackChecks = true;
+    var firstFittingPlacement = placements[0];
 
-        /*:: offsetParent = (offsetParent: Element); */
+    for (var i = 0; i < placements.length; i++) {
+      var placement = placements[i];
 
+      var _basePlacement = getBasePlacement(placement);
 
-        if (placement === top) {
-          sideY = bottom; // $FlowFixMe[prop-missing]
+      var isStartVariation = getVariation(placement) === start;
+      var isVertical = [top, bottom].indexOf(_basePlacement) >= 0;
+      var len = isVertical ? 'width' : 'height';
+      var overflow = detectOverflow(state, {
+        placement: placement,
+        boundary: boundary,
+        rootBoundary: rootBoundary,
+        altBoundary: altBoundary,
+        padding: padding
+      });
+      var mainVariationSide = isVertical ? isStartVariation ? right : left : isStartVariation ? bottom : top;
 
-          y -= offsetParent[heightProp] - popperRect.height;
-          y *= gpuAcceleration ? 1 : -1;
-        }
+      if (referenceRect[len] > popperRect[len]) {
+        mainVariationSide = getOppositePlacement(mainVariationSide);
+      }
 
-        if (placement === left) {
-          sideX = right; // $FlowFixMe[prop-missing]
+      var altVariationSide = getOppositePlacement(mainVariationSide);
+      var checks = [];
 
-          x -= offsetParent[widthProp] - popperRect.width;
-          x *= gpuAcceleration ? 1 : -1;
-        }
+      if (checkMainAxis) {
+        checks.push(overflow[_basePlacement] <= 0);
       }
 
-      var commonStyles = Object.assign({
-        position: position
-      }, adaptive && unsetSides);
-
-      if (gpuAcceleration) {
-        var _Object$assign;
+      if (checkAltAxis) {
+        checks.push(overflow[mainVariationSide] <= 0, overflow[altVariationSide] <= 0);
+      }
 
-        return Object.assign({}, commonStyles, (_Object$assign = {}, _Object$assign[sideY] = hasY ? '0' : '', _Object$assign[sideX] = hasX ? '0' : '', _Object$assign.transform = (win.devicePixelRatio || 1) < 2 ? "translate(" + x + "px, " + y + "px)" : "translate3d(" + x + "px, " + y + "px, 0)", _Object$assign));
+      if (checks.every(function (check) {
+        return check;
+      })) {
+        firstFittingPlacement = placement;
+        makeFallbackChecks = false;
+        break;
       }
 
-      return Object.assign({}, commonStyles, (_Object$assign2 = {}, _Object$assign2[sideY] = hasY ? y + "px" : '', _Object$assign2[sideX] = hasX ? x + "px" : '', _Object$assign2.transform = '', _Object$assign2));
+      checksMap.set(placement, checks);
     }
 
-    function computeStyles(_ref4) {
-      var state = _ref4.state,
-          options = _ref4.options;
-      var _options$gpuAccelerat = options.gpuAcceleration,
-          gpuAcceleration = _options$gpuAccelerat === void 0 ? true : _options$gpuAccelerat,
-          _options$adaptive = options.adaptive,
-          adaptive = _options$adaptive === void 0 ? true : _options$adaptive,
-          _options$roundOffsets = options.roundOffsets,
-          roundOffsets = _options$roundOffsets === void 0 ? true : _options$roundOffsets;
+    if (makeFallbackChecks) {
+      // `2` may be desired in some cases – research later
+      var numberOfChecks = flipVariations ? 3 : 1;
+
+      var _loop = function _loop(_i) {
+        var fittingPlacement = placements.find(function (placement) {
+          var checks = checksMap.get(placement);
+
+          if (checks) {
+            return checks.slice(0, _i).every(function (check) {
+              return check;
+            });
+          }
+        });
 
-      var commonStyles = {
-        placement: getBasePlacement(state.placement),
-        popper: state.elements.popper,
-        popperRect: state.rects.popper,
-        gpuAcceleration: gpuAcceleration
+        if (fittingPlacement) {
+          firstFittingPlacement = fittingPlacement;
+          return "break";
+        }
       };
 
-      if (state.modifiersData.popperOffsets != null) {
-        state.styles.popper = Object.assign({}, state.styles.popper, mapToStyles(Object.assign({}, commonStyles, {
-          offsets: state.modifiersData.popperOffsets,
-          position: state.options.strategy,
-          adaptive: adaptive,
-          roundOffsets: roundOffsets
-        })));
-      }
+      for (var _i = numberOfChecks; _i > 0; _i--) {
+        var _ret = _loop(_i);
 
-      if (state.modifiersData.arrow != null) {
-        state.styles.arrow = Object.assign({}, state.styles.arrow, mapToStyles(Object.assign({}, commonStyles, {
-          offsets: state.modifiersData.arrow,
-          position: 'absolute',
-          adaptive: false,
-          roundOffsets: roundOffsets
-        })));
+        if (_ret === "break") break;
       }
+    }
 
-      state.attributes.popper = Object.assign({}, state.attributes.popper, {
-        'data-popper-placement': state.placement
-      });
-    } // eslint-disable-next-line import/no-unused-modules
+    if (state.placement !== firstFittingPlacement) {
+      state.modifiersData[name]._skip = true;
+      state.placement = firstFittingPlacement;
+      state.reset = true;
+    }
+  } // eslint-disable-next-line import/no-unused-modules
 
 
-    var computeStyles$1 = {
-      name: 'computeStyles',
-      enabled: true,
-      phase: 'beforeWrite',
-      fn: computeStyles,
-      data: {}
-    };
+  var flip$1 = {
+    name: 'flip',
+    enabled: true,
+    phase: 'main',
+    fn: flip,
+    requiresIfExists: ['offset'],
+    data: {
+      _skip: false
+    }
+  };
 
-    var passive = {
-      passive: true
-    };
+  function getSideOffsets(overflow, rect, preventedOffsets) {
+    if (preventedOffsets === void 0) {
+      preventedOffsets = {
+        x: 0,
+        y: 0
+      };
+    }
 
-    function effect$2(_ref) {
-      var state = _ref.state,
-          instance = _ref.instance,
-          options = _ref.options;
-      var _options$scroll = options.scroll,
-          scroll = _options$scroll === void 0 ? true : _options$scroll,
-          _options$resize = options.resize,
-          resize = _options$resize === void 0 ? true : _options$resize;
-      var window = getWindow(state.elements.popper);
-      var scrollParents = [].concat(state.scrollParents.reference, state.scrollParents.popper);
+    return {
+      top: overflow.top - rect.height - preventedOffsets.y,
+      right: overflow.right - rect.width + preventedOffsets.x,
+      bottom: overflow.bottom - rect.height + preventedOffsets.y,
+      left: overflow.left - rect.width - preventedOffsets.x
+    };
+  }
 
-      if (scroll) {
-        scrollParents.forEach(function (scrollParent) {
-          scrollParent.addEventListener('scroll', instance.update, passive);
-        });
-      }
+  function isAnySideFullyClipped(overflow) {
+    return [top, right, bottom, left].some(function (side) {
+      return overflow[side] >= 0;
+    });
+  }
+
+  function hide(_ref) {
+    var state = _ref.state,
+        name = _ref.name;
+    var referenceRect = state.rects.reference;
+    var popperRect = state.rects.popper;
+    var preventedOffsets = state.modifiersData.preventOverflow;
+    var referenceOverflow = detectOverflow(state, {
+      elementContext: 'reference'
+    });
+    var popperAltOverflow = detectOverflow(state, {
+      altBoundary: true
+    });
+    var referenceClippingOffsets = getSideOffsets(referenceOverflow, referenceRect);
+    var popperEscapeOffsets = getSideOffsets(popperAltOverflow, popperRect, preventedOffsets);
+    var isReferenceHidden = isAnySideFullyClipped(referenceClippingOffsets);
+    var hasPopperEscaped = isAnySideFullyClipped(popperEscapeOffsets);
+    state.modifiersData[name] = {
+      referenceClippingOffsets: referenceClippingOffsets,
+      popperEscapeOffsets: popperEscapeOffsets,
+      isReferenceHidden: isReferenceHidden,
+      hasPopperEscaped: hasPopperEscaped
+    };
+    state.attributes.popper = Object.assign({}, state.attributes.popper, {
+      'data-popper-reference-hidden': isReferenceHidden,
+      'data-popper-escaped': hasPopperEscaped
+    });
+  } // eslint-disable-next-line import/no-unused-modules
+
+
+  var hide$1 = {
+    name: 'hide',
+    enabled: true,
+    phase: 'main',
+    requiresIfExists: ['preventOverflow'],
+    fn: hide
+  };
+
+  function distanceAndSkiddingToXY(placement, rects, offset) {
+    var basePlacement = getBasePlacement(placement);
+    var invertDistance = [left, top].indexOf(basePlacement) >= 0 ? -1 : 1;
+
+    var _ref = typeof offset === 'function' ? offset(Object.assign({}, rects, {
+      placement: placement
+    })) : offset,
+        skidding = _ref[0],
+        distance = _ref[1];
+
+    skidding = skidding || 0;
+    distance = (distance || 0) * invertDistance;
+    return [left, right].indexOf(basePlacement) >= 0 ? {
+      x: distance,
+      y: skidding
+    } : {
+      x: skidding,
+      y: distance
+    };
+  }
+
+  function offset(_ref2) {
+    var state = _ref2.state,
+        options = _ref2.options,
+        name = _ref2.name;
+    var _options$offset = options.offset,
+        offset = _options$offset === void 0 ? [0, 0] : _options$offset;
+    var data = placements.reduce(function (acc, placement) {
+      acc[placement] = distanceAndSkiddingToXY(placement, state.rects, offset);
+      return acc;
+    }, {});
+    var _data$state$placement = data[state.placement],
+        x = _data$state$placement.x,
+        y = _data$state$placement.y;
+
+    if (state.modifiersData.popperOffsets != null) {
+      state.modifiersData.popperOffsets.x += x;
+      state.modifiersData.popperOffsets.y += y;
+    }
+
+    state.modifiersData[name] = data;
+  } // eslint-disable-next-line import/no-unused-modules
+
+
+  var offset$1 = {
+    name: 'offset',
+    enabled: true,
+    phase: 'main',
+    requires: ['popperOffsets'],
+    fn: offset
+  };
+
+  function popperOffsets(_ref) {
+    var state = _ref.state,
+        name = _ref.name;
+    // Offsets are the actual position the popper needs to have to be
+    // properly positioned near its reference element
+    // This is the most basic placement, and will be adjusted by
+    // the modifiers in the next step
+    state.modifiersData[name] = computeOffsets({
+      reference: state.rects.reference,
+      element: state.rects.popper,
+      strategy: 'absolute',
+      placement: state.placement
+    });
+  } // eslint-disable-next-line import/no-unused-modules
+
+
+  var popperOffsets$1 = {
+    name: 'popperOffsets',
+    enabled: true,
+    phase: 'read',
+    fn: popperOffsets,
+    data: {}
+  };
+
+  function getAltAxis(axis) {
+    return axis === 'x' ? 'y' : 'x';
+  }
+
+  function preventOverflow(_ref) {
+    var state = _ref.state,
+        options = _ref.options,
+        name = _ref.name;
+    var _options$mainAxis = options.mainAxis,
+        checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis,
+        _options$altAxis = options.altAxis,
+        checkAltAxis = _options$altAxis === void 0 ? false : _options$altAxis,
+        boundary = options.boundary,
+        rootBoundary = options.rootBoundary,
+        altBoundary = options.altBoundary,
+        padding = options.padding,
+        _options$tether = options.tether,
+        tether = _options$tether === void 0 ? true : _options$tether,
+        _options$tetherOffset = options.tetherOffset,
+        tetherOffset = _options$tetherOffset === void 0 ? 0 : _options$tetherOffset;
+    var overflow = detectOverflow(state, {
+      boundary: boundary,
+      rootBoundary: rootBoundary,
+      padding: padding,
+      altBoundary: altBoundary
+    });
+    var basePlacement = getBasePlacement(state.placement);
+    var variation = getVariation(state.placement);
+    var isBasePlacement = !variation;
+    var mainAxis = getMainAxisFromPlacement(basePlacement);
+    var altAxis = getAltAxis(mainAxis);
+    var popperOffsets = state.modifiersData.popperOffsets;
+    var referenceRect = state.rects.reference;
+    var popperRect = state.rects.popper;
+    var tetherOffsetValue = typeof tetherOffset === 'function' ? tetherOffset(Object.assign({}, state.rects, {
+      placement: state.placement
+    })) : tetherOffset;
+    var data = {
+      x: 0,
+      y: 0
+    };
 
-      if (resize) {
-        window.addEventListener('resize', instance.update, passive);
-      }
+    if (!popperOffsets) {
+      return;
+    }
 
-      return function () {
-        if (scroll) {
-          scrollParents.forEach(function (scrollParent) {
-            scrollParent.removeEventListener('scroll', instance.update, passive);
-          });
-        }
+    if (checkMainAxis || checkAltAxis) {
+      var mainSide = mainAxis === 'y' ? top : left;
+      var altSide = mainAxis === 'y' ? bottom : right;
+      var len = mainAxis === 'y' ? 'height' : 'width';
+      var offset = popperOffsets[mainAxis];
+      var min$1 = popperOffsets[mainAxis] + overflow[mainSide];
+      var max$1 = popperOffsets[mainAxis] - overflow[altSide];
+      var additive = tether ? -popperRect[len] / 2 : 0;
+      var minLen = variation === start ? referenceRect[len] : popperRect[len];
+      var maxLen = variation === start ? -popperRect[len] : -referenceRect[len]; // We need to include the arrow in the calculation so the arrow doesn't go
+      // outside the reference bounds
 
-        if (resize) {
-          window.removeEventListener('resize', instance.update, passive);
-        }
+      var arrowElement = state.elements.arrow;
+      var arrowRect = tether && arrowElement ? getLayoutRect(arrowElement) : {
+        width: 0,
+        height: 0
       };
-    } // eslint-disable-next-line import/no-unused-modules
+      var arrowPaddingObject = state.modifiersData['arrow#persistent'] ? state.modifiersData['arrow#persistent'].padding : getFreshSideObject();
+      var arrowPaddingMin = arrowPaddingObject[mainSide];
+      var arrowPaddingMax = arrowPaddingObject[altSide]; // If the reference length is smaller than the arrow length, we don't want
+      // to include its full size in the calculation. If the reference is small
+      // and near the edge of a boundary, the popper can overflow even if the
+      // reference is not overflowing as well (e.g. virtual elements with no
+      // width or height)
 
+      var arrowLen = within(0, referenceRect[len], arrowRect[len]);
+      var minOffset = isBasePlacement ? referenceRect[len] / 2 - additive - arrowLen - arrowPaddingMin - tetherOffsetValue : minLen - arrowLen - arrowPaddingMin - tetherOffsetValue;
+      var maxOffset = isBasePlacement ? -referenceRect[len] / 2 + additive + arrowLen + arrowPaddingMax + tetherOffsetValue : maxLen + arrowLen + arrowPaddingMax + tetherOffsetValue;
+      var arrowOffsetParent = state.elements.arrow && getOffsetParent(state.elements.arrow);
+      var clientOffset = arrowOffsetParent ? mainAxis === 'y' ? arrowOffsetParent.clientTop || 0 : arrowOffsetParent.clientLeft || 0 : 0;
+      var offsetModifierValue = state.modifiersData.offset ? state.modifiersData.offset[state.placement][mainAxis] : 0;
+      var tetherMin = popperOffsets[mainAxis] + minOffset - offsetModifierValue - clientOffset;
+      var tetherMax = popperOffsets[mainAxis] + maxOffset - offsetModifierValue;
 
-    var eventListeners = {
-      name: 'eventListeners',
-      enabled: true,
-      phase: 'write',
-      fn: function fn() {},
-      effect: effect$2,
-      data: {}
-    };
+      if (checkMainAxis) {
+        var preventedOffset = within(tether ? min(min$1, tetherMin) : min$1, offset, tether ? max(max$1, tetherMax) : max$1);
+        popperOffsets[mainAxis] = preventedOffset;
+        data[mainAxis] = preventedOffset - offset;
+      }
 
-    var hash = {
-      left: 'right',
-      right: 'left',
-      bottom: 'top',
-      top: 'bottom'
-    };
-    function getOppositePlacement(placement) {
-      return placement.replace(/left|right|bottom|top/g, function (matched) {
-        return hash[matched];
-      });
-    }
+      if (checkAltAxis) {
+        var _mainSide = mainAxis === 'x' ? top : left;
 
-    var hash$1 = {
-      start: 'end',
-      end: 'start'
-    };
-    function getOppositeVariationPlacement(placement) {
-      return placement.replace(/start|end/g, function (matched) {
-        return hash$1[matched];
-      });
-    }
+        var _altSide = mainAxis === 'x' ? bottom : right;
 
-    function getBoundingClientRect(element) {
-      var rect = element.getBoundingClientRect();
-      return {
-        width: rect.width,
-        height: rect.height,
-        top: rect.top,
-        right: rect.right,
-        bottom: rect.bottom,
-        left: rect.left,
-        x: rect.left,
-        y: rect.top
-      };
-    }
+        var _offset = popperOffsets[altAxis];
 
-    function getWindowScroll(node) {
-      var win = getWindow(node);
-      var scrollLeft = win.pageXOffset;
-      var scrollTop = win.pageYOffset;
-      return {
-        scrollLeft: scrollLeft,
-        scrollTop: scrollTop
-      };
-    }
+        var _min = _offset + overflow[_mainSide];
 
-    function getWindowScrollBarX(element) {
-      // If <html> has a CSS width greater than the viewport, then this will be
-      // incorrect for RTL.
-      // Popper 1 is broken in this case and never had a bug report so let's assume
-      // it's not an issue. I don't think anyone ever specifies width on <html>
-      // anyway.
-      // Browsers where the left scrollbar doesn't cause an issue report `0` for
-      // this (e.g. Edge 2019, IE11, Safari)
-      return getBoundingClientRect(getDocumentElement(element)).left + getWindowScroll(element).scrollLeft;
-    }
-
-    function getViewportRect(element) {
-      var win = getWindow(element);
-      var html = getDocumentElement(element);
-      var visualViewport = win.visualViewport;
-      var width = html.clientWidth;
-      var height = html.clientHeight;
-      var x = 0;
-      var y = 0; // NB: This isn't supported on iOS <= 12. If the keyboard is open, the popper
-      // can be obscured underneath it.
-      // Also, `html.clientHeight` adds the bottom bar height in Safari iOS, even
-      // if it isn't open, so if this isn't available, the popper will be detected
-      // to overflow the bottom of the screen too early.
-
-      if (visualViewport) {
-        width = visualViewport.width;
-        height = visualViewport.height; // Uses Layout Viewport (like Chrome; Safari does not currently)
-        // In Chrome, it returns a value very close to 0 (+/-) but contains rounding
-        // errors due to floating point numbers, so we need to check precision.
-        // Safari returns a number <= 0, usually < -1 when pinch-zoomed
-        // Feature detection fails in mobile emulation mode in Chrome.
-        // Math.abs(win.innerWidth / visualViewport.scale - visualViewport.width) <
-        // 0.001
-        // Fallback here: "Not Safari" userAgent
-
-        if (!/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) {
-          x = visualViewport.offsetLeft;
-          y = visualViewport.offsetTop;
-        }
-      }
+        var _max = _offset - overflow[_altSide];
 
-      return {
-        width: width,
-        height: height,
-        x: x + getWindowScrollBarX(element),
-        y: y
-      };
+        var _preventedOffset = within(tether ? min(_min, tetherMin) : _min, _offset, tether ? max(_max, tetherMax) : _max);
+
+        popperOffsets[altAxis] = _preventedOffset;
+        data[altAxis] = _preventedOffset - _offset;
+      }
     }
 
-    // of the `<html>` and `<body>` rect bounds if horizontally scrollable
+    state.modifiersData[name] = data;
+  } // eslint-disable-next-line import/no-unused-modules
 
-    function getDocumentRect(element) {
-      var _element$ownerDocumen;
 
-      var html = getDocumentElement(element);
-      var winScroll = getWindowScroll(element);
-      var body = (_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body;
-      var width = max(html.scrollWidth, html.clientWidth, body ? body.scrollWidth : 0, body ? body.clientWidth : 0);
-      var height = max(html.scrollHeight, html.clientHeight, body ? body.scrollHeight : 0, body ? body.clientHeight : 0);
-      var x = -winScroll.scrollLeft + getWindowScrollBarX(element);
-      var y = -winScroll.scrollTop;
+  var preventOverflow$1 = {
+    name: 'preventOverflow',
+    enabled: true,
+    phase: 'main',
+    fn: preventOverflow,
+    requiresIfExists: ['offset']
+  };
 
-      if (getComputedStyle$1(body || html).direction === 'rtl') {
-        x += max(html.clientWidth, body ? body.clientWidth : 0) - width;
-      }
+  function getHTMLElementScroll(element) {
+    return {
+      scrollLeft: element.scrollLeft,
+      scrollTop: element.scrollTop
+    };
+  }
 
-      return {
-        width: width,
-        height: height,
-        x: x,
-        y: y
-      };
+  function getNodeScroll(node) {
+    if (node === getWindow(node) || !isHTMLElement(node)) {
+      return getWindowScroll(node);
+    } else {
+      return getHTMLElementScroll(node);
     }
+  }
 
-    function isScrollParent(element) {
-      // Firefox wants us to check `-x` and `-y` variations as well
-      var _getComputedStyle = getComputedStyle$1(element),
-          overflow = _getComputedStyle.overflow,
-          overflowX = _getComputedStyle.overflowX,
-          overflowY = _getComputedStyle.overflowY;
+  // Composite means it takes into account transforms as well as layout.
 
-      return /auto|scroll|overlay|hidden/.test(overflow + overflowY + overflowX);
+  function getCompositeRect(elementOrVirtualElement, offsetParent, isFixed) {
+    if (isFixed === void 0) {
+      isFixed = false;
     }
 
-    function getScrollParent(node) {
-      if (['html', 'body', '#document'].indexOf(getNodeName(node)) >= 0) {
-        // $FlowFixMe[incompatible-return]: assume body is always available
-        return node.ownerDocument.body;
+    var documentElement = getDocumentElement(offsetParent);
+    var rect = getBoundingClientRect(elementOrVirtualElement);
+    var isOffsetParentAnElement = isHTMLElement(offsetParent);
+    var scroll = {
+      scrollLeft: 0,
+      scrollTop: 0
+    };
+    var offsets = {
+      x: 0,
+      y: 0
+    };
+
+    if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) {
+      if (getNodeName(offsetParent) !== 'body' || // https://github.com/popperjs/popper-core/issues/1078
+      isScrollParent(documentElement)) {
+        scroll = getNodeScroll(offsetParent);
       }
 
-      if (isHTMLElement(node) && isScrollParent(node)) {
-        return node;
+      if (isHTMLElement(offsetParent)) {
+        offsets = getBoundingClientRect(offsetParent);
+        offsets.x += offsetParent.clientLeft;
+        offsets.y += offsetParent.clientTop;
+      } else if (documentElement) {
+        offsets.x = getWindowScrollBarX(documentElement);
       }
+    }
+
+    return {
+      x: rect.left + scroll.scrollLeft - offsets.x,
+      y: rect.top + scroll.scrollTop - offsets.y,
+      width: rect.width,
+      height: rect.height
+    };
+  }
+
+  function order(modifiers) {
+    var map = new Map();
+    var visited = new Set();
+    var result = [];
+    modifiers.forEach(function (modifier) {
+      map.set(modifier.name, modifier);
+    }); // On visiting object, check for its dependencies and visit them recursively
 
-      return getScrollParent(getParentNode(node));
+    function sort(modifier) {
+      visited.add(modifier.name);
+      var requires = [].concat(modifier.requires || [], modifier.requiresIfExists || []);
+      requires.forEach(function (dep) {
+        if (!visited.has(dep)) {
+          var depModifier = map.get(dep);
+
+          if (depModifier) {
+            sort(depModifier);
+          }
+        }
+      });
+      result.push(modifier);
     }
 
-    /*
-    given a DOM element, return the list of all scroll parents, up the list of ancesors
-    until we get to the top window object. This list is what we attach scroll listeners
-    to, because if any of these parent elements scroll, we'll need to re-calculate the
-    reference element's position.
-    */
+    modifiers.forEach(function (modifier) {
+      if (!visited.has(modifier.name)) {
+        // check for visited object
+        sort(modifier);
+      }
+    });
+    return result;
+  }
 
-    function listScrollParents(element, list) {
-      var _element$ownerDocumen;
+  function orderModifiers(modifiers) {
+    // order based on dependencies
+    var orderedModifiers = order(modifiers); // order based on phase
 
-      if (list === void 0) {
-        list = [];
+    return modifierPhases.reduce(function (acc, phase) {
+      return acc.concat(orderedModifiers.filter(function (modifier) {
+        return modifier.phase === phase;
+      }));
+    }, []);
+  }
+
+  function debounce(fn) {
+    var pending;
+    return function () {
+      if (!pending) {
+        pending = new Promise(function (resolve) {
+          Promise.resolve().then(function () {
+            pending = undefined;
+            resolve(fn());
+          });
+        });
       }
 
-      var scrollParent = getScrollParent(element);
-      var isBody = scrollParent === ((_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body);
-      var win = getWindow(scrollParent);
-      var target = isBody ? [win].concat(win.visualViewport || [], isScrollParent(scrollParent) ? scrollParent : []) : scrollParent;
-      var updatedList = list.concat(target);
-      return isBody ? updatedList : // $FlowFixMe[incompatible-call]: isBody tells us target will be an HTMLElement here
-      updatedList.concat(listScrollParents(getParentNode(target)));
-    }
+      return pending;
+    };
+  }
+
+  function mergeByName(modifiers) {
+    var merged = modifiers.reduce(function (merged, current) {
+      var existing = merged[current.name];
+      merged[current.name] = existing ? Object.assign({}, existing, current, {
+        options: Object.assign({}, existing.options, current.options),
+        data: Object.assign({}, existing.data, current.data)
+      }) : current;
+      return merged;
+    }, {}); // IE11 does not support Object.values
+
+    return Object.keys(merged).map(function (key) {
+      return merged[key];
+    });
+  }
 
-    function rectToClientRect(rect) {
-      return Object.assign({}, rect, {
-        left: rect.x,
-        top: rect.y,
-        right: rect.x + rect.width,
-        bottom: rect.y + rect.height
-      });
+  var DEFAULT_OPTIONS = {
+    placement: 'bottom',
+    modifiers: [],
+    strategy: 'absolute'
+  };
+
+  function areValidElements() {
+    for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
+      args[_key] = arguments[_key];
     }
 
-    function getInnerBoundingClientRect(element) {
-      var rect = getBoundingClientRect(element);
-      rect.top = rect.top + element.clientTop;
-      rect.left = rect.left + element.clientLeft;
-      rect.bottom = rect.top + element.clientHeight;
-      rect.right = rect.left + element.clientWidth;
-      rect.width = element.clientWidth;
-      rect.height = element.clientHeight;
-      rect.x = rect.left;
-      rect.y = rect.top;
-      return rect;
+    return !args.some(function (element) {
+      return !(element && typeof element.getBoundingClientRect === 'function');
+    });
+  }
+
+  function popperGenerator(generatorOptions) {
+    if (generatorOptions === void 0) {
+      generatorOptions = {};
     }
 
-    function getClientRectFromMixedType(element, clippingParent) {
-      return clippingParent === viewport ? rectToClientRect(getViewportRect(element)) : isHTMLElement(clippingParent) ? getInnerBoundingClientRect(clippingParent) : rectToClientRect(getDocumentRect(getDocumentElement(element)));
-    } // A "clipping parent" is an overflowable container with the characteristic of
-    // clipping (or hiding) overflowing elements with a position different from
-    // `initial`
+    var _generatorOptions = generatorOptions,
+        _generatorOptions$def = _generatorOptions.defaultModifiers,
+        defaultModifiers = _generatorOptions$def === void 0 ? [] : _generatorOptions$def,
+        _generatorOptions$def2 = _generatorOptions.defaultOptions,
+        defaultOptions = _generatorOptions$def2 === void 0 ? DEFAULT_OPTIONS : _generatorOptions$def2;
+    return function createPopper(reference, popper, options) {
+      if (options === void 0) {
+        options = defaultOptions;
+      }
 
+      var state = {
+        placement: 'bottom',
+        orderedModifiers: [],
+        options: Object.assign({}, DEFAULT_OPTIONS, defaultOptions),
+        modifiersData: {},
+        elements: {
+          reference: reference,
+          popper: popper
+        },
+        attributes: {},
+        styles: {}
+      };
+      var effectCleanupFns = [];
+      var isDestroyed = false;
+      var instance = {
+        state: state,
+        setOptions: function setOptions(options) {
+          cleanupModifierEffects();
+          state.options = Object.assign({}, defaultOptions, state.options, options);
+          state.scrollParents = {
+            reference: isElement(reference) ? listScrollParents(reference) : reference.contextElement ? listScrollParents(reference.contextElement) : [],
+            popper: listScrollParents(popper)
+          }; // Orders the modifiers based on their dependencies and `phase`
+          // properties
+
+          var orderedModifiers = orderModifiers(mergeByName([].concat(defaultModifiers, state.options.modifiers))); // Strip out disabled modifiers
+
+          state.orderedModifiers = orderedModifiers.filter(function (m) {
+            return m.enabled;
+          }); // Validate the provided modifiers so that the consumer will get warned
+
+          runModifierEffects();
+          return instance.update();
+        },
+        // Sync update – it will always be executed, even if not necessary. This
+        // is useful for low frequency updates where sync behavior simplifies the
+        // logic.
+        // For high frequency updates (e.g. `resize` and `scroll` events), always
+        // prefer the async Popper#update method
+        forceUpdate: function forceUpdate() {
+          if (isDestroyed) {
+            return;
+          }
 
-    function getClippingParents(element) {
-      var clippingParents = listScrollParents(getParentNode(element));
-      var canEscapeClipping = ['absolute', 'fixed'].indexOf(getComputedStyle$1(element).position) >= 0;
-      var clipperElement = canEscapeClipping && isHTMLElement(element) ? getOffsetParent(element) : element;
+          var _state$elements = state.elements,
+              reference = _state$elements.reference,
+              popper = _state$elements.popper; // Don't proceed if `reference` or `popper` are not valid elements
+          // anymore
 
-      if (!isElement(clipperElement)) {
-        return [];
-      } // $FlowFixMe[incompatible-return]: https://github.com/facebook/flow/issues/1414
+          if (!areValidElements(reference, popper)) {
 
+            return;
+          } // Store the reference and popper rects to be read by modifiers
+
+
+          state.rects = {
+            reference: getCompositeRect(reference, getOffsetParent(popper), state.options.strategy === 'fixed'),
+            popper: getLayoutRect(popper)
+          }; // Modifiers have the ability to reset the current update cycle. The
+          // most common use case for this is the `flip` modifier changing the
+          // placement, which then needs to re-run all the modifiers, because the
+          // logic was previously ran for the previous placement and is therefore
+          // stale/incorrect
+
+          state.reset = false;
+          state.placement = state.options.placement; // On each update cycle, the `modifiersData` property for each modifier
+          // is filled with the initial data specified by the modifier. This means
+          // it doesn't persist and is fresh on each update.
+          // To ensure persistent data, use `${name}#persistent`
+
+          state.orderedModifiers.forEach(function (modifier) {
+            return state.modifiersData[modifier.name] = Object.assign({}, modifier.data);
+          });
 
-      return clippingParents.filter(function (clippingParent) {
-        return isElement(clippingParent) && contains(clippingParent, clipperElement) && getNodeName(clippingParent) !== 'body';
-      });
-    } // Gets the maximum area that the element is visible in due to any number of
-    // clipping parents
-
-
-    function getClippingRect(element, boundary, rootBoundary) {
-      var mainClippingParents = boundary === 'clippingParents' ? getClippingParents(element) : [].concat(boundary);
-      var clippingParents = [].concat(mainClippingParents, [rootBoundary]);
-      var firstClippingParent = clippingParents[0];
-      var clippingRect = clippingParents.reduce(function (accRect, clippingParent) {
-        var rect = getClientRectFromMixedType(element, clippingParent);
-        accRect.top = max(rect.top, accRect.top);
-        accRect.right = min(rect.right, accRect.right);
-        accRect.bottom = min(rect.bottom, accRect.bottom);
-        accRect.left = max(rect.left, accRect.left);
-        return accRect;
-      }, getClientRectFromMixedType(element, firstClippingParent));
-      clippingRect.width = clippingRect.right - clippingRect.left;
-      clippingRect.height = clippingRect.bottom - clippingRect.top;
-      clippingRect.x = clippingRect.left;
-      clippingRect.y = clippingRect.top;
-      return clippingRect;
-    }
-
-    function getVariation(placement) {
-      return placement.split('-')[1];
-    }
-
-    function computeOffsets(_ref) {
-      var reference = _ref.reference,
-          element = _ref.element,
-          placement = _ref.placement;
-      var basePlacement = placement ? getBasePlacement(placement) : null;
-      var variation = placement ? getVariation(placement) : null;
-      var commonX = reference.x + reference.width / 2 - element.width / 2;
-      var commonY = reference.y + reference.height / 2 - element.height / 2;
-      var offsets;
-
-      switch (basePlacement) {
-        case top:
-          offsets = {
-            x: commonX,
-            y: reference.y - element.height
-          };
-          break;
+          for (var index = 0; index < state.orderedModifiers.length; index++) {
 
-        case bottom:
-          offsets = {
-            x: commonX,
-            y: reference.y + reference.height
-          };
-          break;
+            if (state.reset === true) {
+              state.reset = false;
+              index = -1;
+              continue;
+            }
 
-        case right:
-          offsets = {
-            x: reference.x + reference.width,
-            y: commonY
-          };
-          break;
+            var _state$orderedModifie = state.orderedModifiers[index],
+                fn = _state$orderedModifie.fn,
+                _state$orderedModifie2 = _state$orderedModifie.options,
+                _options = _state$orderedModifie2 === void 0 ? {} : _state$orderedModifie2,
+                name = _state$orderedModifie.name;
 
-        case left:
-          offsets = {
-            x: reference.x - element.width,
-            y: commonY
-          };
-          break;
+            if (typeof fn === 'function') {
+              state = fn({
+                state: state,
+                options: _options,
+                name: name,
+                instance: instance
+              }) || state;
+            }
+          }
+        },
+        // Async and optimistically optimized update – it will not be executed if
+        // not necessary (debounced to run at most once-per-tick)
+        update: debounce(function () {
+          return new Promise(function (resolve) {
+            instance.forceUpdate();
+            resolve(state);
+          });
+        }),
+        destroy: function destroy() {
+          cleanupModifierEffects();
+          isDestroyed = true;
+        }
+      };
 
-        default:
-          offsets = {
-            x: reference.x,
-            y: reference.y
-          };
+      if (!areValidElements(reference, popper)) {
+
+        return instance;
       }
 
-      var mainAxis = basePlacement ? getMainAxisFromPlacement(basePlacement) : null;
+      instance.setOptions(options).then(function (state) {
+        if (!isDestroyed && options.onFirstUpdate) {
+          options.onFirstUpdate(state);
+        }
+      }); // Modifiers have the ability to execute arbitrary code before the first
+      // update cycle runs. They will be executed in the same order as the update
+      // cycle. This is useful when a modifier adds some persistent data that
+      // other modifiers need to use, but the modifier is run after the dependent
+      // one.
+
+      function runModifierEffects() {
+        state.orderedModifiers.forEach(function (_ref3) {
+          var name = _ref3.name,
+              _ref3$options = _ref3.options,
+              options = _ref3$options === void 0 ? {} : _ref3$options,
+              effect = _ref3.effect;
+
+          if (typeof effect === 'function') {
+            var cleanupFn = effect({
+              state: state,
+              name: name,
+              instance: instance,
+              options: options
+            });
 
-      if (mainAxis != null) {
-        var len = mainAxis === 'y' ? 'height' : 'width';
+            var noopFn = function noopFn() {};
 
-        switch (variation) {
-          case start:
-            offsets[mainAxis] = offsets[mainAxis] - (reference[len] / 2 - element[len] / 2);
-            break;
+            effectCleanupFns.push(cleanupFn || noopFn);
+          }
+        });
+      }
 
-          case end:
-            offsets[mainAxis] = offsets[mainAxis] + (reference[len] / 2 - element[len] / 2);
-            break;
-        }
+      function cleanupModifierEffects() {
+        effectCleanupFns.forEach(function (fn) {
+          return fn();
+        });
+        effectCleanupFns = [];
       }
 
-      return offsets;
+      return instance;
+    };
+  }
+  var createPopper = /*#__PURE__*/popperGenerator(); // eslint-disable-next-line import/no-unused-modules
+
+  var defaultModifiers = [eventListeners, popperOffsets$1, computeStyles$1, applyStyles$1];
+  var createPopper$1 = /*#__PURE__*/popperGenerator({
+    defaultModifiers: defaultModifiers
+  }); // eslint-disable-next-line import/no-unused-modules
+
+  var defaultModifiers$1 = [eventListeners, popperOffsets$1, computeStyles$1, applyStyles$1, offset$1, flip$1, preventOverflow$1, arrow$1, hide$1];
+  var createPopper$2 = /*#__PURE__*/popperGenerator({
+    defaultModifiers: defaultModifiers$1
+  }); // eslint-disable-next-line import/no-unused-modules
+
+  var Popper = /*#__PURE__*/Object.freeze({
+    __proto__: null,
+    popperGenerator: popperGenerator,
+    detectOverflow: detectOverflow,
+    createPopperBase: createPopper,
+    createPopper: createPopper$2,
+    createPopperLite: createPopper$1,
+    top: top,
+    bottom: bottom,
+    right: right,
+    left: left,
+    auto: auto,
+    basePlacements: basePlacements,
+    start: start,
+    end: end,
+    clippingParents: clippingParents,
+    viewport: viewport,
+    popper: popper,
+    reference: reference,
+    variationPlacements: variationPlacements,
+    placements: placements,
+    beforeRead: beforeRead,
+    read: read,
+    afterRead: afterRead,
+    beforeMain: beforeMain,
+    main: main,
+    afterMain: afterMain,
+    beforeWrite: beforeWrite,
+    write: write,
+    afterWrite: afterWrite,
+    modifierPhases: modifierPhases,
+    applyStyles: applyStyles$1,
+    arrow: arrow$1,
+    computeStyles: computeStyles$1,
+    eventListeners: eventListeners,
+    flip: flip$1,
+    hide: hide$1,
+    offset: offset$1,
+    popperOffsets: popperOffsets$1,
+    preventOverflow: preventOverflow$1
+  });
+
+  /*!
+    * Bootstrap v5.0.0-beta2 (https://getbootstrap.com/)
+    * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
+    * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+    */
+
+  function _defineProperties(target, props) {
+    for (var i = 0; i < props.length; i++) {
+      var descriptor = props[i];
+      descriptor.enumerable = descriptor.enumerable || false;
+      descriptor.configurable = true;
+      if ("value" in descriptor) descriptor.writable = true;
+      Object.defineProperty(target, descriptor.key, descriptor);
     }
+  }
 
-    function detectOverflow(state, options) {
-      if (options === void 0) {
-        options = {};
-      }
-
-      var _options = options,
-          _options$placement = _options.placement,
-          placement = _options$placement === void 0 ? state.placement : _options$placement,
-          _options$boundary = _options.boundary,
-          boundary = _options$boundary === void 0 ? clippingParents : _options$boundary,
-          _options$rootBoundary = _options.rootBoundary,
-          rootBoundary = _options$rootBoundary === void 0 ? viewport : _options$rootBoundary,
-          _options$elementConte = _options.elementContext,
-          elementContext = _options$elementConte === void 0 ? popper : _options$elementConte,
-          _options$altBoundary = _options.altBoundary,
-          altBoundary = _options$altBoundary === void 0 ? false : _options$altBoundary,
-          _options$padding = _options.padding,
-          padding = _options$padding === void 0 ? 0 : _options$padding;
-      var paddingObject = mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements));
-      var altContext = elementContext === popper ? reference : popper;
-      var referenceElement = state.elements.reference;
-      var popperRect = state.rects.popper;
-      var element = state.elements[altBoundary ? altContext : elementContext];
-      var clippingClientRect = getClippingRect(isElement(element) ? element : element.contextElement || getDocumentElement(state.elements.popper), boundary, rootBoundary);
-      var referenceClientRect = getBoundingClientRect(referenceElement);
-      var popperOffsets = computeOffsets({
-        reference: referenceClientRect,
-        element: popperRect,
-        strategy: 'absolute',
-        placement: placement
-      });
-      var popperClientRect = rectToClientRect(Object.assign({}, popperRect, popperOffsets));
-      var elementClientRect = elementContext === popper ? popperClientRect : referenceClientRect; // positive = overflowing the clipping rect
-      // 0 or negative = within the clipping rect
-
-      var overflowOffsets = {
-        top: clippingClientRect.top - elementClientRect.top + paddingObject.top,
-        bottom: elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom,
-        left: clippingClientRect.left - elementClientRect.left + paddingObject.left,
-        right: elementClientRect.right - clippingClientRect.right + paddingObject.right
-      };
-      var offsetData = state.modifiersData.offset; // Offsets can be applied only to the popper element
-
-      if (elementContext === popper && offsetData) {
-        var offset = offsetData[placement];
-        Object.keys(overflowOffsets).forEach(function (key) {
-          var multiply = [right, bottom].indexOf(key) >= 0 ? 1 : -1;
-          var axis = [top, bottom].indexOf(key) >= 0 ? 'y' : 'x';
-          overflowOffsets[key] += offset[axis] * multiply;
-        });
+  function _createClass(Constructor, protoProps, staticProps) {
+    if (protoProps) _defineProperties(Constructor.prototype, protoProps);
+    if (staticProps) _defineProperties(Constructor, staticProps);
+    return Constructor;
+  }
+
+  function _extends() {
+    _extends = Object.assign || function (target) {
+      for (var i = 1; i < arguments.length; i++) {
+        var source = arguments[i];
+
+        for (var key in source) {
+          if (Object.prototype.hasOwnProperty.call(source, key)) {
+            target[key] = source[key];
+          }
+        }
       }
 
-      return overflowOffsets;
-    }
+      return target;
+    };
 
-    /*:: type OverflowsMap = { [ComputedPlacement]: number }; */
+    return _extends.apply(this, arguments);
+  }
 
-    /*;; type OverflowsMap = { [key in ComputedPlacement]: number }; */
-    function computeAutoPlacement(state, options) {
-      if (options === void 0) {
-        options = {};
-      }
-
-      var _options = options,
-          placement = _options.placement,
-          boundary = _options.boundary,
-          rootBoundary = _options.rootBoundary,
-          padding = _options.padding,
-          flipVariations = _options.flipVariations,
-          _options$allowedAutoP = _options.allowedAutoPlacements,
-          allowedAutoPlacements = _options$allowedAutoP === void 0 ? placements : _options$allowedAutoP;
-      var variation = getVariation(placement);
-      var placements$1 = variation ? flipVariations ? variationPlacements : variationPlacements.filter(function (placement) {
-        return getVariation(placement) === variation;
-      }) : basePlacements;
-      var allowedPlacements = placements$1.filter(function (placement) {
-        return allowedAutoPlacements.indexOf(placement) >= 0;
-      });
+  function _inheritsLoose(subClass, superClass) {
+    subClass.prototype = Object.create(superClass.prototype);
+    subClass.prototype.constructor = subClass;
 
-      if (allowedPlacements.length === 0) {
-        allowedPlacements = placements$1;
-      } // $FlowFixMe[incompatible-type]: Flow seems to have problems with two array unions...
+    _setPrototypeOf(subClass, superClass);
+  }
 
+  function _setPrototypeOf(o, p) {
+    _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
+      o.__proto__ = p;
+      return o;
+    };
 
-      var overflows = allowedPlacements.reduce(function (acc, placement) {
-        acc[placement] = detectOverflow(state, {
-          placement: placement,
-          boundary: boundary,
-          rootBoundary: rootBoundary,
-          padding: padding
-        })[getBasePlacement(placement)];
-        return acc;
-      }, {});
-      return Object.keys(overflows).sort(function (a, b) {
-        return overflows[a] - overflows[b];
-      });
-    }
+    return _setPrototypeOf(o, p);
+  }
 
-    function getExpandedFallbackPlacements(placement) {
-      if (getBasePlacement(placement) === auto) {
-        return [];
-      }
+  /**
+   * --------------------------------------------------------------------------
+   * Bootstrap (v5.0.0-beta2): util/index.js
+   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+   * --------------------------------------------------------------------------
+   */
+  var MAX_UID = 1000000;
+  var MILLISECONDS_MULTIPLIER = 1000;
+  var TRANSITION_END = 'transitionend'; // Shoutout AngusCroll (https://goo.gl/pxwQGp)
 
-      var oppositePlacement = getOppositePlacement(placement);
-      return [getOppositeVariationPlacement(placement), oppositePlacement, getOppositeVariationPlacement(oppositePlacement)];
+  var toType = function toType(obj) {
+    if (obj === null || obj === undefined) {
+      return "" + obj;
     }
 
-    function flip(_ref) {
-      var state = _ref.state,
-          options = _ref.options,
-          name = _ref.name;
+    return {}.toString.call(obj).match(/\s([a-z]+)/i)[1].toLowerCase();
+  };
+  /**
+   * --------------------------------------------------------------------------
+   * Public Util Api
+   * --------------------------------------------------------------------------
+   */
 
-      if (state.modifiersData[name]._skip) {
-        return;
-      }
 
-      var _options$mainAxis = options.mainAxis,
-          checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis,
-          _options$altAxis = options.altAxis,
-          checkAltAxis = _options$altAxis === void 0 ? true : _options$altAxis,
-          specifiedFallbackPlacements = options.fallbackPlacements,
-          padding = options.padding,
-          boundary = options.boundary,
-          rootBoundary = options.rootBoundary,
-          altBoundary = options.altBoundary,
-          _options$flipVariatio = options.flipVariations,
-          flipVariations = _options$flipVariatio === void 0 ? true : _options$flipVariatio,
-          allowedAutoPlacements = options.allowedAutoPlacements;
-      var preferredPlacement = state.options.placement;
-      var basePlacement = getBasePlacement(preferredPlacement);
-      var isBasePlacement = basePlacement === preferredPlacement;
-      var fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipVariations ? [getOppositePlacement(preferredPlacement)] : getExpandedFallbackPlacements(preferredPlacement));
-      var placements = [preferredPlacement].concat(fallbackPlacements).reduce(function (acc, placement) {
-        return acc.concat(getBasePlacement(placement) === auto ? computeAutoPlacement(state, {
-          placement: placement,
-          boundary: boundary,
-          rootBoundary: rootBoundary,
-          padding: padding,
-          flipVariations: flipVariations,
-          allowedAutoPlacements: allowedAutoPlacements
-        }) : placement);
-      }, []);
-      var referenceRect = state.rects.reference;
-      var popperRect = state.rects.popper;
-      var checksMap = new Map();
-      var makeFallbackChecks = true;
-      var firstFittingPlacement = placements[0];
-
-      for (var i = 0; i < placements.length; i++) {
-        var placement = placements[i];
-
-        var _basePlacement = getBasePlacement(placement);
-
-        var isStartVariation = getVariation(placement) === start;
-        var isVertical = [top, bottom].indexOf(_basePlacement) >= 0;
-        var len = isVertical ? 'width' : 'height';
-        var overflow = detectOverflow(state, {
-          placement: placement,
-          boundary: boundary,
-          rootBoundary: rootBoundary,
-          altBoundary: altBoundary,
-          padding: padding
-        });
-        var mainVariationSide = isVertical ? isStartVariation ? right : left : isStartVariation ? bottom : top;
+  var getUID = function getUID(prefix) {
+    do {
+      prefix += Math.floor(Math.random() * MAX_UID);
+    } while (document.getElementById(prefix));
 
-        if (referenceRect[len] > popperRect[len]) {
-          mainVariationSide = getOppositePlacement(mainVariationSide);
-        }
+    return prefix;
+  };
 
-        var altVariationSide = getOppositePlacement(mainVariationSide);
-        var checks = [];
+  var getSelector = function getSelector(element) {
+    var selector = element.getAttribute('data-bs-target');
 
-        if (checkMainAxis) {
-          checks.push(overflow[_basePlacement] <= 0);
-        }
+    if (!selector || selector === '#') {
+      var hrefAttr = element.getAttribute('href'); // The only valid content that could double as a selector are IDs or classes,
+      // so everything starting with `#` or `.`. If a "real" URL is used as the selector,
+      // `document.querySelector` will rightfully complain it is invalid.
+      // See https://github.com/twbs/bootstrap/issues/32273
 
-        if (checkAltAxis) {
-          checks.push(overflow[mainVariationSide] <= 0, overflow[altVariationSide] <= 0);
-        }
+      if (!hrefAttr || !hrefAttr.includes('#') && !hrefAttr.startsWith('.')) {
+        return null;
+      } // Just in case some CMS puts out a full URL with the anchor appended
 
-        if (checks.every(function (check) {
-          return check;
-        })) {
-          firstFittingPlacement = placement;
-          makeFallbackChecks = false;
-          break;
-        }
 
-        checksMap.set(placement, checks);
+      if (hrefAttr.includes('#') && !hrefAttr.startsWith('#')) {
+        hrefAttr = '#' + hrefAttr.split('#')[1];
       }
 
-      if (makeFallbackChecks) {
-        // `2` may be desired in some cases – research later
-        var numberOfChecks = flipVariations ? 3 : 1;
+      selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : null;
+    }
 
-        var _loop = function _loop(_i) {
-          var fittingPlacement = placements.find(function (placement) {
-            var checks = checksMap.get(placement);
+    return selector;
+  };
 
-            if (checks) {
-              return checks.slice(0, _i).every(function (check) {
-                return check;
-              });
-            }
-          });
+  var getSelectorFromElement = function getSelectorFromElement(element) {
+    var selector = getSelector(element);
 
-          if (fittingPlacement) {
-            firstFittingPlacement = fittingPlacement;
-            return "break";
-          }
-        };
+    if (selector) {
+      return document.querySelector(selector) ? selector : null;
+    }
 
-        for (var _i = numberOfChecks; _i > 0; _i--) {
-          var _ret = _loop(_i);
+    return null;
+  };
 
-          if (_ret === "break") break;
-        }
-      }
+  var getElementFromSelector = function getElementFromSelector(element) {
+    var selector = getSelector(element);
+    return selector ? document.querySelector(selector) : null;
+  };
 
-      if (state.placement !== firstFittingPlacement) {
-        state.modifiersData[name]._skip = true;
-        state.placement = firstFittingPlacement;
-        state.reset = true;
-      }
-    } // eslint-disable-next-line import/no-unused-modules
+  var getTransitionDurationFromElement = function getTransitionDurationFromElement(element) {
+    if (!element) {
+      return 0;
+    } // Get transition-duration of the element
 
 
-    var flip$1 = {
-      name: 'flip',
-      enabled: true,
-      phase: 'main',
-      fn: flip,
-      requiresIfExists: ['offset'],
-      data: {
-        _skip: false
-      }
-    };
+    var _window$getComputedSt = window.getComputedStyle(element),
+        transitionDuration = _window$getComputedSt.transitionDuration,
+        transitionDelay = _window$getComputedSt.transitionDelay;
 
-    function getSideOffsets(overflow, rect, preventedOffsets) {
-      if (preventedOffsets === void 0) {
-        preventedOffsets = {
-          x: 0,
-          y: 0
-        };
-      }
+    var floatTransitionDuration = Number.parseFloat(transitionDuration);
+    var floatTransitionDelay = Number.parseFloat(transitionDelay); // Return 0 if element or transition duration is not found
 
-      return {
-        top: overflow.top - rect.height - preventedOffsets.y,
-        right: overflow.right - rect.width + preventedOffsets.x,
-        bottom: overflow.bottom - rect.height + preventedOffsets.y,
-        left: overflow.left - rect.width - preventedOffsets.x
-      };
-    }
+    if (!floatTransitionDuration && !floatTransitionDelay) {
+      return 0;
+    } // If multiple durations are defined, take the first
 
-    function isAnySideFullyClipped(overflow) {
-      return [top, right, bottom, left].some(function (side) {
-        return overflow[side] >= 0;
-      });
-    }
 
-    function hide(_ref) {
-      var state = _ref.state,
-          name = _ref.name;
-      var referenceRect = state.rects.reference;
-      var popperRect = state.rects.popper;
-      var preventedOffsets = state.modifiersData.preventOverflow;
-      var referenceOverflow = detectOverflow(state, {
-        elementContext: 'reference'
-      });
-      var popperAltOverflow = detectOverflow(state, {
-        altBoundary: true
-      });
-      var referenceClippingOffsets = getSideOffsets(referenceOverflow, referenceRect);
-      var popperEscapeOffsets = getSideOffsets(popperAltOverflow, popperRect, preventedOffsets);
-      var isReferenceHidden = isAnySideFullyClipped(referenceClippingOffsets);
-      var hasPopperEscaped = isAnySideFullyClipped(popperEscapeOffsets);
-      state.modifiersData[name] = {
-        referenceClippingOffsets: referenceClippingOffsets,
-        popperEscapeOffsets: popperEscapeOffsets,
-        isReferenceHidden: isReferenceHidden,
-        hasPopperEscaped: hasPopperEscaped
-      };
-      state.attributes.popper = Object.assign({}, state.attributes.popper, {
-        'data-popper-reference-hidden': isReferenceHidden,
-        'data-popper-escaped': hasPopperEscaped
-      });
-    } // eslint-disable-next-line import/no-unused-modules
-
-
-    var hide$1 = {
-      name: 'hide',
-      enabled: true,
-      phase: 'main',
-      requiresIfExists: ['preventOverflow'],
-      fn: hide
-    };
-
-    function distanceAndSkiddingToXY(placement, rects, offset) {
-      var basePlacement = getBasePlacement(placement);
-      var invertDistance = [left, top].indexOf(basePlacement) >= 0 ? -1 : 1;
-
-      var _ref = typeof offset === 'function' ? offset(Object.assign({}, rects, {
-        placement: placement
-      })) : offset,
-          skidding = _ref[0],
-          distance = _ref[1];
-
-      skidding = skidding || 0;
-      distance = (distance || 0) * invertDistance;
-      return [left, right].indexOf(basePlacement) >= 0 ? {
-        x: distance,
-        y: skidding
-      } : {
-        x: skidding,
-        y: distance
-      };
+    transitionDuration = transitionDuration.split(',')[0];
+    transitionDelay = transitionDelay.split(',')[0];
+    return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER;
+  };
+
+  var triggerTransitionEnd = function triggerTransitionEnd(element) {
+    element.dispatchEvent(new Event(TRANSITION_END));
+  };
+
+  var isElement$1 = function isElement(obj) {
+    return (obj[0] || obj).nodeType;
+  };
+
+  var emulateTransitionEnd = function emulateTransitionEnd(element, duration) {
+    var called = false;
+    var durationPadding = 5;
+    var emulatedDuration = duration + durationPadding;
+
+    function listener() {
+      called = true;
+      element.removeEventListener(TRANSITION_END, listener);
     }
 
-    function offset(_ref2) {
-      var state = _ref2.state,
-          options = _ref2.options,
-          name = _ref2.name;
-      var _options$offset = options.offset,
-          offset = _options$offset === void 0 ? [0, 0] : _options$offset;
-      var data = placements.reduce(function (acc, placement) {
-        acc[placement] = distanceAndSkiddingToXY(placement, state.rects, offset);
-        return acc;
-      }, {});
-      var _data$state$placement = data[state.placement],
-          x = _data$state$placement.x,
-          y = _data$state$placement.y;
-
-      if (state.modifiersData.popperOffsets != null) {
-        state.modifiersData.popperOffsets.x += x;
-        state.modifiersData.popperOffsets.y += y;
-      }
-
-      state.modifiersData[name] = data;
-    } // eslint-disable-next-line import/no-unused-modules
-
-
-    var offset$1 = {
-      name: 'offset',
-      enabled: true,
-      phase: 'main',
-      requires: ['popperOffsets'],
-      fn: offset
-    };
-
-    function popperOffsets(_ref) {
-      var state = _ref.state,
-          name = _ref.name;
-      // Offsets are the actual position the popper needs to have to be
-      // properly positioned near its reference element
-      // This is the most basic placement, and will be adjusted by
-      // the modifiers in the next step
-      state.modifiersData[name] = computeOffsets({
-        reference: state.rects.reference,
-        element: state.rects.popper,
-        strategy: 'absolute',
-        placement: state.placement
-      });
-    } // eslint-disable-next-line import/no-unused-modules
-
-
-    var popperOffsets$1 = {
-      name: 'popperOffsets',
-      enabled: true,
-      phase: 'read',
-      fn: popperOffsets,
-      data: {}
-    };
-
-    function getAltAxis(axis) {
-      return axis === 'x' ? 'y' : 'x';
-    }
-
-    function preventOverflow(_ref) {
-      var state = _ref.state,
-          options = _ref.options,
-          name = _ref.name;
-      var _options$mainAxis = options.mainAxis,
-          checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis,
-          _options$altAxis = options.altAxis,
-          checkAltAxis = _options$altAxis === void 0 ? false : _options$altAxis,
-          boundary = options.boundary,
-          rootBoundary = options.rootBoundary,
-          altBoundary = options.altBoundary,
-          padding = options.padding,
-          _options$tether = options.tether,
-          tether = _options$tether === void 0 ? true : _options$tether,
-          _options$tetherOffset = options.tetherOffset,
-          tetherOffset = _options$tetherOffset === void 0 ? 0 : _options$tetherOffset;
-      var overflow = detectOverflow(state, {
-        boundary: boundary,
-        rootBoundary: rootBoundary,
-        padding: padding,
-        altBoundary: altBoundary
-      });
-      var basePlacement = getBasePlacement(state.placement);
-      var variation = getVariation(state.placement);
-      var isBasePlacement = !variation;
-      var mainAxis = getMainAxisFromPlacement(basePlacement);
-      var altAxis = getAltAxis(mainAxis);
-      var popperOffsets = state.modifiersData.popperOffsets;
-      var referenceRect = state.rects.reference;
-      var popperRect = state.rects.popper;
-      var tetherOffsetValue = typeof tetherOffset === 'function' ? tetherOffset(Object.assign({}, state.rects, {
-        placement: state.placement
-      })) : tetherOffset;
-      var data = {
-        x: 0,
-        y: 0
-      };
+    element.addEventListener(TRANSITION_END, listener);
+    setTimeout(function () {
+      if (!called) {
+        triggerTransitionEnd(element);
+      }
+    }, emulatedDuration);
+  };
 
-      if (!popperOffsets) {
-        return;
+  var typeCheckConfig = function typeCheckConfig(componentName, config, configTypes) {
+    Object.keys(configTypes).forEach(function (property) {
+      var expectedTypes = configTypes[property];
+      var value = config[property];
+      var valueType = value && isElement$1(value) ? 'element' : toType(value);
+
+      if (!new RegExp(expectedTypes).test(valueType)) {
+        throw new TypeError(componentName.toUpperCase() + ": " + ("Option \"" + property + "\" provided type \"" + valueType + "\" ") + ("but expected type \"" + expectedTypes + "\"."));
       }
+    });
+  };
 
-      if (checkMainAxis || checkAltAxis) {
-        var mainSide = mainAxis === 'y' ? top : left;
-        var altSide = mainAxis === 'y' ? bottom : right;
-        var len = mainAxis === 'y' ? 'height' : 'width';
-        var offset = popperOffsets[mainAxis];
-        var min$1 = popperOffsets[mainAxis] + overflow[mainSide];
-        var max$1 = popperOffsets[mainAxis] - overflow[altSide];
-        var additive = tether ? -popperRect[len] / 2 : 0;
-        var minLen = variation === start ? referenceRect[len] : popperRect[len];
-        var maxLen = variation === start ? -popperRect[len] : -referenceRect[len]; // We need to include the arrow in the calculation so the arrow doesn't go
-        // outside the reference bounds
-
-        var arrowElement = state.elements.arrow;
-        var arrowRect = tether && arrowElement ? getLayoutRect(arrowElement) : {
-          width: 0,
-          height: 0
-        };
-        var arrowPaddingObject = state.modifiersData['arrow#persistent'] ? state.modifiersData['arrow#persistent'].padding : getFreshSideObject();
-        var arrowPaddingMin = arrowPaddingObject[mainSide];
-        var arrowPaddingMax = arrowPaddingObject[altSide]; // If the reference length is smaller than the arrow length, we don't want
-        // to include its full size in the calculation. If the reference is small
-        // and near the edge of a boundary, the popper can overflow even if the
-        // reference is not overflowing as well (e.g. virtual elements with no
-        // width or height)
+  var isVisible = function isVisible(element) {
+    if (!element) {
+      return false;
+    }
 
-        var arrowLen = within(0, referenceRect[len], arrowRect[len]);
-        var minOffset = isBasePlacement ? referenceRect[len] / 2 - additive - arrowLen - arrowPaddingMin - tetherOffsetValue : minLen - arrowLen - arrowPaddingMin - tetherOffsetValue;
-        var maxOffset = isBasePlacement ? -referenceRect[len] / 2 + additive + arrowLen + arrowPaddingMax + tetherOffsetValue : maxLen + arrowLen + arrowPaddingMax + tetherOffsetValue;
-        var arrowOffsetParent = state.elements.arrow && getOffsetParent(state.elements.arrow);
-        var clientOffset = arrowOffsetParent ? mainAxis === 'y' ? arrowOffsetParent.clientTop || 0 : arrowOffsetParent.clientLeft || 0 : 0;
-        var offsetModifierValue = state.modifiersData.offset ? state.modifiersData.offset[state.placement][mainAxis] : 0;
-        var tetherMin = popperOffsets[mainAxis] + minOffset - offsetModifierValue - clientOffset;
-        var tetherMax = popperOffsets[mainAxis] + maxOffset - offsetModifierValue;
+    if (element.style && element.parentNode && element.parentNode.style) {
+      var elementStyle = getComputedStyle(element);
+      var parentNodeStyle = getComputedStyle(element.parentNode);
+      return elementStyle.display !== 'none' && parentNodeStyle.display !== 'none' && elementStyle.visibility !== 'hidden';
+    }
 
-        if (checkMainAxis) {
-          var preventedOffset = within(tether ? min(min$1, tetherMin) : min$1, offset, tether ? max(max$1, tetherMax) : max$1);
-          popperOffsets[mainAxis] = preventedOffset;
-          data[mainAxis] = preventedOffset - offset;
-        }
+    return false;
+  };
 
-        if (checkAltAxis) {
-          var _mainSide = mainAxis === 'x' ? top : left;
+  var findShadowRoot = function findShadowRoot(element) {
+    if (!document.documentElement.attachShadow) {
+      return null;
+    } // Can find the shadow root otherwise it'll return the document
 
-          var _altSide = mainAxis === 'x' ? bottom : right;
 
-          var _offset = popperOffsets[altAxis];
+    if (typeof element.getRootNode === 'function') {
+      var root = element.getRootNode();
+      return root instanceof ShadowRoot ? root : null;
+    }
 
-          var _min = _offset + overflow[_mainSide];
+    if (element instanceof ShadowRoot) {
+      return element;
+    } // when we don't find a shadow root
 
-          var _max = _offset - overflow[_altSide];
 
-          var _preventedOffset = within(tether ? min(_min, tetherMin) : _min, _offset, tether ? max(_max, tetherMax) : _max);
+    if (!element.parentNode) {
+      return null;
+    }
 
-          popperOffsets[altAxis] = _preventedOffset;
-          data[altAxis] = _preventedOffset - _offset;
-        }
-      }
+    return findShadowRoot(element.parentNode);
+  };
 
-      state.modifiersData[name] = data;
-    } // eslint-disable-next-line import/no-unused-modules
+  var noop = function noop() {
+    return function () {};
+  };
 
+  var reflow = function reflow(element) {
+    return element.offsetHeight;
+  };
 
-    var preventOverflow$1 = {
-      name: 'preventOverflow',
-      enabled: true,
-      phase: 'main',
-      fn: preventOverflow,
-      requiresIfExists: ['offset']
-    };
+  var getjQuery = function getjQuery() {
+    var _window = window,
+        jQuery = _window.jQuery;
 
-    function getHTMLElementScroll(element) {
-      return {
-        scrollLeft: element.scrollLeft,
-        scrollTop: element.scrollTop
-      };
+    if (jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {
+      return jQuery;
     }
 
-    function getNodeScroll(node) {
-      if (node === getWindow(node) || !isHTMLElement(node)) {
-        return getWindowScroll(node);
-      } else {
-        return getHTMLElementScroll(node);
-      }
+    return null;
+  };
+
+  var onDOMContentLoaded = function onDOMContentLoaded(callback) {
+    if (document.readyState === 'loading') {
+      document.addEventListener('DOMContentLoaded', callback);
+    } else {
+      callback();
     }
+  };
+
+  var isRTL = document.documentElement.dir === 'rtl';
+
+  var defineJQueryPlugin = function defineJQueryPlugin(name, plugin) {
+    onDOMContentLoaded(function () {
+      var $ = getjQuery();
+      /* istanbul ignore if */
 
-    // Composite means it takes into account transforms as well as layout.
+      if ($) {
+        var JQUERY_NO_CONFLICT = $.fn[name];
+        $.fn[name] = plugin.jQueryInterface;
+        $.fn[name].Constructor = plugin;
 
-    function getCompositeRect(elementOrVirtualElement, offsetParent, isFixed) {
-      if (isFixed === void 0) {
-        isFixed = false;
+        $.fn[name].noConflict = function () {
+          $.fn[name] = JQUERY_NO_CONFLICT;
+          return plugin.jQueryInterface;
+        };
       }
+    });
+  };
+
+  /**
+   * --------------------------------------------------------------------------
+   * Bootstrap (v5.0.0-beta2): dom/data.js
+   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+   * --------------------------------------------------------------------------
+   */
+
+  /**
+   * ------------------------------------------------------------------------
+   * Constants
+   * ------------------------------------------------------------------------
+   */
+  var mapData = function () {
+    var storeData = {};
+    var id = 1;
+    return {
+      set: function set(element, key, data) {
+        if (typeof element.bsKey === 'undefined') {
+          element.bsKey = {
+            key: key,
+            id: id
+          };
+          id++;
+        }
 
-      var documentElement = getDocumentElement(offsetParent);
-      var rect = getBoundingClientRect(elementOrVirtualElement);
-      var isOffsetParentAnElement = isHTMLElement(offsetParent);
-      var scroll = {
-        scrollLeft: 0,
-        scrollTop: 0
-      };
-      var offsets = {
-        x: 0,
-        y: 0
-      };
+        storeData[element.bsKey.id] = data;
+      },
+      get: function get(element, key) {
+        if (!element || typeof element.bsKey === 'undefined') {
+          return null;
+        }
+
+        var keyProperties = element.bsKey;
 
-      if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) {
-        if (getNodeName(offsetParent) !== 'body' || // https://github.com/popperjs/popper-core/issues/1078
-        isScrollParent(documentElement)) {
-          scroll = getNodeScroll(offsetParent);
+        if (keyProperties.key === key) {
+          return storeData[keyProperties.id];
         }
 
-        if (isHTMLElement(offsetParent)) {
-          offsets = getBoundingClientRect(offsetParent);
-          offsets.x += offsetParent.clientLeft;
-          offsets.y += offsetParent.clientTop;
-        } else if (documentElement) {
-          offsets.x = getWindowScrollBarX(documentElement);
+        return null;
+      },
+      delete: function _delete(element, key) {
+        if (typeof element.bsKey === 'undefined') {
+          return;
         }
-      }
 
-      return {
-        x: rect.left + scroll.scrollLeft - offsets.x,
-        y: rect.top + scroll.scrollTop - offsets.y,
-        width: rect.width,
-        height: rect.height
-      };
-    }
+        var keyProperties = element.bsKey;
+
+        if (keyProperties.key === key) {
+          delete storeData[keyProperties.id];
+          delete element.bsKey;
+        }
+      }
+    };
+  }();
+
+  var Data = {
+    setData: function setData(instance, key, data) {
+      mapData.set(instance, key, data);
+    },
+    getData: function getData(instance, key) {
+      return mapData.get(instance, key);
+    },
+    removeData: function removeData(instance, key) {
+      mapData.delete(instance, key);
+    }
+  };
+
+  /**
+   * --------------------------------------------------------------------------
+   * Bootstrap (v5.0.0-beta2): dom/event-handler.js
+   * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+   * --------------------------------------------------------------------------
+   */
+  /**
+   * ------------------------------------------------------------------------
+   * Constants
+   * ------------------------------------------------------------------------
+   */
+
+  var namespaceRegex = /[^.]*(?=\..*)\.|.*/;
+  var stripNameRegex = /\..*/;
+  var stripUidRegex = /::\d+$/;
+  var eventRegistry = {}; // Events storage
+
+  var uidEvent = 1;
+  var customEvents = {
+    mouseenter: 'mouseover',
+    mouseleave: 'mouseout'
+  };
+  var nativeEvents = new Set(['click', 'dblclick', 'mouseup', 'mousedown', 'contextmenu', 'mousewheel', 'DOMMouseScroll', 'mouseover', 'mouseout', 'mousemove', 'selectstart', 'selectend', 'keydown', 'keypress', 'keyup', 'orientationchange', 'touchstart', 'touchmove', 'touchend', 'touchcancel', 'pointerdown', 'pointermove', 'pointerup', 'pointerleave', 'pointercancel', 'gesturestart', 'gesturechange', 'gestureend', 'focus', 'blur', 'change', 'reset', 'select', 'submit', 'focusin', 'focuso [...]
+  /**
+   * ------------------------------------------------------------------------
+   * Private methods
+   * ------------------------------------------------------------------------
+   */
+
+  function getUidEvent(element, uid) {
+    return uid && uid + "::" + uidEvent++ || element.uidEvent || uidEvent++;
+  }
+
+  function getEvent(element) {
+    var uid = getUidEvent(element);
+    element.uidEvent = uid;
+    eventRegistry[uid] = eventRegistry[uid] || {};
+    return eventRegistry[uid];
+  }
+
+  function bootstrapHandler(element, fn) {
+    return function handler(event) {
+      event.delegateTarget = element;
+
+      if (handler.oneOff) {
+        EventHandler.off(element, event.type, fn);
+      }
+
+      return fn.apply(element, [event]);
+    };
+  }
 
-    function order(modifiers) {
-      var map = new Map();
-      var visited = new Set();
-      var result = [];
-      modifiers.forEach(function (modifier) {
-        map.set(modifier.name, modifier);
-      }); // On visiting object, check for its dependencies and visit them recursively
+  function bootstrapDelegationHandler(element, selector, fn) {
+    return function handler(event) {
+      var domElements = element.querySelectorAll(selector);
 
-      function sort(modifier) {
-        visited.add(modifier.name);
-        var requires = [].concat(modifier.requires || [], modifier.requiresIfExists || []);
-        requires.forEach(function (dep) {
-          if (!visited.has(dep)) {
-            var depModifier = map.get(dep);
+      for (var target = event.target; target && target !== this; target = target.parentNode) {
+        for (var i = domElements.length; i--;) {
+          if (domElements[i] === target) {
+            event.delegateTarget = target;
 
-            if (depModifier) {
-              sort(depModifier);
+            if (handler.oneOff) {
+              // eslint-disable-next-line unicorn/consistent-destructuring
+              EventHandler.off(element, event.type, fn);
             }
-          }
-        });
-        result.push(modifier);
-      }
 
-      modifiers.forEach(function (modifier) {
-        if (!visited.has(modifier.name)) {
-          // check for visited object
-          sort(modifier);
+            return fn.apply(target, [event]);
+          }
         }
-      });
-      return result;
+      } // To please ESLint
+
+
+      return null;
+    };
+  }
+
+  function findHandler(events, handler, delegationSelector) {
+    if (delegationSelector === void 0) {
+      delegationSelector = null;
     }
 
-    function orderModifiers(modifiers) {
-      // order based on dependencies
-      var orderedModifiers = order(modifiers); // order based on phase
+    var uidEventList = Object.keys(events);
 
-      return modifierPhases.reduce(function (acc, phase) {
-        return acc.concat(orderedModifiers.filter(function (modifier) {
-          return modifier.phase === phase;
-        }));
-      }, []);
+    for (var i = 0, len = uidEventList.length; i < len; i++) {
+      var event = events[uidEventList[i]];
+
+      if (event.originalHandler === handler && event.delegationSelector === delegationSelector) {
+        return event;
+      }
     }
 
-    function debounce(fn) {
-      var pending;
-      return function () {
-        if (!pending) {
-          pending = new Promise(function (resolve) {
-            Promise.resolve().then(function () {
-              pending = undefined;
-              resolve(fn());
-            });
-          });
-        }
+    return null;
+  }
 
-        return pending;
-      };
+  function normalizeParams(originalTypeEvent, handler, delegationFn) {
+    var delegation = typeof handler === 'string';
+    var originalHandler = delegation ? delegationFn : handler; // allow to get the native events from namespaced events ('click.bs.button' --> 'click')
+
+    var typeEvent = originalTypeEvent.replace(stripNameRegex, '');
+    var custom = customEvents[typeEvent];
+
+    if (custom) {
+      typeEvent = custom;
     }
 
-    function mergeByName(modifiers) {
-      var merged = modifiers.reduce(function (merged, current) {
-        var existing = merged[current.name];
-        merged[current.name] = existing ? Object.assign({}, existing, current, {
-          options: Object.assign({}, existing.options, current.options),
-          data: Object.assign({}, existing.data, current.data)
-        }) : current;
-        return merged;
-      }, {}); // IE11 does not support Object.values
+    var isNative = nativeEvents.has(typeEvent);
 
-      return Object.keys(merged).map(function (key) {
-        return merged[key];
-      });
+    if (!isNative) {
+      typeEvent = originalTypeEvent;
     }
 
-    var DEFAULT_OPTIONS = {
-      placement: 'bottom',
-      modifiers: [],
-      strategy: 'absolute'
-    };
+    return [delegation, originalHandler, typeEvent];
+  }
 
-    function areValidElements() {
-      for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
-        args[_key] = arguments[_key];
-      }
+  function addHandler(element, originalTypeEvent, handler, delegationFn, oneOff) {
+    if (typeof originalTypeEvent !== 'string' || !element) {
+      return;
+    }
 
-      return !args.some(function (element) {
-        return !(element && typeof element.getBoundingClientRect === 'function');
-      });
+    if (!handler) {
+      handler = delegationFn;
+      delegationFn = null;
     }
 
-    function popperGenerator(generatorOptions) {
-      if (generatorOptions === void 0) {
-        generatorOptions = {};
-      }
+    var _normalizeParams = normalizeParams(originalTypeEvent, handler, delegationFn),
+        delegation = _normalizeParams[0],
+        originalHandler = _normalizeParams[1],
+        typeEvent = _normalizeParams[2];
 
-      var _generatorOptions = generatorOptions,
-          _generatorOptions$def = _generatorOptions.defaultModifiers,
-          defaultModifiers = _generatorOptions$def === void 0 ? [] : _generatorOptions$def,
-          _generatorOptions$def2 = _generatorOptions.defaultOptions,
-          defaultOptions = _generatorOptions$def2 === void 0 ? DEFAULT_OPTIONS : _generatorOptions$def2;
-      return function createPopper(reference, popper, options) {
-        if (options === void 0) {
-          options = defaultOptions;
-        }
+    var events = getEvent(element);
+    var handlers = events[typeEvent] || (events[typeEvent] = {});
+    var previousFn = findHandler(handlers, originalHandler, delegation ? handler : null);
 
-        var state = {
-          placement: 'bottom',
-          orderedModifiers: [],
-          options: Object.assign({}, DEFAULT_OPTIONS, defaultOptions),
-          modifiersData: {},
-          elements: {
-            reference: reference,
-            popper: popper
-          },
-          attributes: {},
-          styles: {}
-        };
-        var effectCleanupFns = [];
-        var isDestroyed = false;
-        var instance = {
-          state: state,
-          setOptions: function setOptions(options) {
-            cleanupModifierEffects();
-            state.options = Object.assign({}, defaultOptions, state.options, options);
-            state.scrollParents = {
-              reference: isElement(reference) ? listScrollParents(reference) : reference.contextElement ? listScrollParents(reference.contextElement) : [],
-              popper: listScrollParents(popper)
-            }; // Orders the modifiers based on their dependencies and `phase`
-            // properties
-
-            var orderedModifiers = orderModifiers(mergeByName([].concat(defaultModifiers, state.options.modifiers))); // Strip out disabled modifiers
-
-            state.orderedModifiers = orderedModifiers.filter(function (m) {
-              return m.enabled;
-            }); // Validate the provided modifiers so that the consumer will get warned
-
-            runModifierEffects();
-            return instance.update();
-          },
-          // Sync update – it will always be executed, even if not necessary. This
-          // is useful for low frequency updates where sync behavior simplifies the
-          // logic.
-          // For high frequency updates (e.g. `resize` and `scroll` events), always
-          // prefer the async Popper#update method
-          forceUpdate: function forceUpdate() {
-            if (isDestroyed) {
-              return;
-            }
+    if (previousFn) {
+      previousFn.oneOff = previousFn.oneOff && oneOff;
+      return;
+    }
 
-            var _state$elements = state.elements,
-                reference = _state$elements.reference,
-                popper = _state$elements.popper; // Don't proceed if `reference` or `popper` are not valid elements
-            // anymore
+    var uid = getUidEvent(originalHandler, originalTypeEvent.replace(namespaceRegex, ''));
+    var fn = delegation ? bootstrapDelegationHandler(element, handler, delegationFn) : bootstrapHandler(element, handler);
+    fn.delegationSelector = delegation ? handler : null;
+    fn.originalHandler = originalHandler;
+    fn.oneOff = oneOff;
+    fn.uidEvent = uid;
+    handlers[uid] = fn;
+    element.addEventListener(typeEvent, fn, delegation);
+  }
 
-            if (!areValidElements(reference, popper)) {
+  function removeHandler(element, events, typeEvent, handler, delegationSelector) {
+    var fn = findHandler(events[typeEvent], handler, delegationSelector);
 
-              return;
-            } // Store the reference and popper rects to be read by modifiers
-
-
-            state.rects = {
-              reference: getCompositeRect(reference, getOffsetParent(popper), state.options.strategy === 'fixed'),
-              popper: getLayoutRect(popper)
-            }; // Modifiers have the ability to reset the current update cycle. The
-            // most common use case for this is the `flip` modifier changing the
-            // placement, which then needs to re-run all the modifiers, because the
-            // logic was previously ran for the previous placement and is therefore
-            // stale/incorrect
-
-            state.reset = false;
-            state.placement = state.options.placement; // On each update cycle, the `modifiersData` property for each modifier
-            // is filled with the initial data specified by the modifier. This means
-            // it doesn't persist and is fresh on each update.
-            // To ensure persistent data, use `${name}#persistent`
-
-            state.orderedModifiers.forEach(function (modifier) {
-              return state.modifiersData[modifier.name] = Object.assign({}, modifier.data);
-            });
+    if (!fn) {
+      return;
+    }
 
-            for (var index = 0; index < state.orderedModifiers.length; index++) {
+    element.removeEventListener(typeEvent, fn, Boolean(delegationSelector));
+    delete events[typeEvent][fn.uidEvent];
+  }
 
-              if (state.reset === true) {
-                state.reset = false;
-                index = -1;
-                continue;
-              }
+  function removeNamespacedHandlers(element, events, typeEvent, namespace) {
+    var storeElementEvent = events[typeEvent] || {};
+    Object.keys(storeElementEvent).forEach(function (handlerKey) {
+      if (handlerKey.includes(namespace)) {
+        var event = storeElementEvent[handlerKey];
+        removeHandler(element, events, typeEvent, event.originalHandler, event.delegationSelector);
+      }
+    });
+  }
+
+  var EventHandler = {
+    on: function on(element, event, handler, delegationFn) {
+      addHandler(element, event, handler, delegationFn, false);
+    },
+    one: function one(element, event, handler, delegationFn) {
+      addHandler(element, event, handler, delegationFn, true);
+    },
+    off: function off(element, originalTypeEvent, handler, delegationFn) {
+      if (typeof originalTypeEvent !== 'string' || !element) {
+        return;
+      }
 
-              var _state$orderedModifie = state.orderedModifiers[index],
-                  fn = _state$orderedModifie.fn,
-                  _state$orderedModifie2 = _state$orderedModifie.options,
-                  _options = _state$orderedModifie2 === void 0 ? {} : _state$orderedModifie2,
-                  name = _state$orderedModifie.name;
-
-              if (typeof fn === 'function') {
-                state = fn({
-                  state: state,
-                  options: _options,
-                  name: name,
-                  instance: instance
-                }) || state;
-              }
-            }
-          },
-          // Async and optimistically optimized update – it will not be executed if
-          // not necessary (debounced to run at most once-per-tick)
-          update: debounce(function () {
-            return new Promise(function (resolve) {
-              instance.forceUpdate();
-              resolve(state);
-            });
-          }),
-          destroy: function destroy() {
-            cleanupModifierEffects();
-            isDestroyed = true;
-          }
-        };
+      var _normalizeParams2 = normalizeParams(originalTypeEvent, handler, delegationFn),
+          delegation = _normalizeParams2[0],
+          originalHandler = _normalizeParams2[1],
+          typeEvent = _normalizeParams2[2];
 
-        if (!areValidElements(reference, popper)) {
+      var inNamespace = typeEvent !== originalTypeEvent;
+      var events = getEvent(element);
+      var isNamespace = originalTypeEvent.startsWith('.');
 
-          return instance;
+      if (typeof originalHandler !== 'undefined') {
+        // Simplest case: handler is passed, remove that listener ONLY.
+        if (!events || !events[typeEvent]) {
+          return;
         }
 
-        instance.setOptions(options).then(function (state) {
-          if (!isDestroyed && options.onFirstUpdate) {
-            options.onFirstUpdate(state);
-          }
-        }); // Modifiers have the ability to execute arbitrary code before the first
-        // update cycle runs. They will be executed in the same order as the update
-        // cycle. This is useful when a modifier adds some persistent data that
-        // other modifiers need to use, but the modifier is run after the dependent
-        // one.
-
-        function runModifierEffects() {
-          state.orderedModifiers.forEach(function (_ref3) {
-            var name = _ref3.name,
-                _ref3$options = _ref3.options,
-                options = _ref3$options === void 0 ? {} : _ref3$options,
-                effect = _ref3.effect;
+        removeHandler(element, events, typeEvent, originalHandler, delegation ? handler : null);
+        return;
+      }
 
-            if (typeof effect === 'function') {
-              var cleanupFn = effect({
-                state: state,
-                name: name,
-                instance: instance,
-                options: options
-              });
+      if (isNamespace) {
+        Object.keys(events).forEach(function (elementEvent) {
+          removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1));
+        });
+      }
 
-              var noopFn = function noopFn() {};
+      var storeElementEvent = events[typeEvent] || {};
+      Object.keys(storeElementEvent).forEach(function (keyHandlers) {
+        var handlerKey = keyHandlers.replace(stripUidRegex, '');
 
-              effectCleanupFns.push(cleanupFn || noopFn);
-            }
-          });
+        if (!inNamespace || originalTypeEvent.includes(handlerKey)) {
+          var event = storeElementEvent[keyHandlers];
+          removeHandler(element, events, typeEvent, event.originalHandler, event.delegationSelector);
         }
+      });
+    },
+    trigger: function trigger(element, event, args) {
+      if (typeof event !== 'string' || !element) {
+        return null;
+      }
 
-        function cleanupModifierEffects() {
-          effectCleanupFns.forEach(function (fn) {
-            return fn();
-          });
-          effectCleanupFns = [];
-        }
+      var $ = getjQuery();
+      var typeEvent = event.replace(stripNameRegex, '');
+      var inNamespace = event !== typeEvent;
+      var isNative = nativeEvents.has(typeEvent);
+      var jQueryEvent;
+      var bubbles = true;
+      var nativeDispatch = true;
+      var defaultPrevented = false;
+      var evt = null;
... 17395 lines suppressed ...