[
  {
    "path": ".browserslistrc",
    "content": "> 1%\n"
  },
  {
    "path": ".codebeatignore",
    "content": "public/**\nwebpack.config.*.js\n*.js"
  },
  {
    "path": ".codecov.yml",
    "content": "coverage:\n  parsers:\n    javascript:\n      enable_partials: yes\n"
  },
  {
    "path": ".editorconfig",
    "content": "\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true"
  },
  {
    "path": ".eslintrc.json",
    "content": "{\n  \"parser\": \"@typescript-eslint/parser\",\n  \"plugins\": [\"@typescript-eslint\", \"prettier\", \"sort-class-members\"],\n  \"extends\": [\n    \"airbnb-base\",\n    \"airbnb-typescript\",\n    \"plugin:prettier/recommended\",\n    \"plugin:compat/recommended\",\n    \"plugin:@typescript-eslint/recommended\"\n  ],\n  \"env\": {\n    \"es6\": true,\n    \"node\": true,\n    \"browser\": true\n  },\n  \"parserOptions\": {\n    \"sourceType\": \"module\",\n    \"project\": true\n  },\n  \"rules\": {\n    \"no-param-reassign\": [\"error\", { \"props\": false }],\n    \"@typescript-eslint/explicit-function-return-type\": \"error\",\n    \"import/no-named-as-default\": \"off\",\n    \"import/prefer-default-export\": \"off\",\n    \"import/no-extraneous-dependencies\": [\n      \"error\",\n      {\n        \"devDependencies\": true\n      }\n    ],\n    \"no-console\": [\n      \"warn\",\n      {\n        \"allow\": [\"warn\", \"error\"]\n      }\n    ],\n    \"no-plusplus\": \"off\",\n    \"no-unused-expressions\": \"off\",\n    \"no-underscore-dangle\": \"off\",\n    \"consistent-return\": \"off\",\n    \"import/no-useless-path-segments\": \"warn\",\n    \"prefer-destructuring\": [\n      \"warn\",\n      {\n        \"array\": false,\n        \"object\": true\n      }\n    ],\n    \"curly\": [\"error\", \"all\"],\n    \"newline-before-return\": \"error\",\n    \"sort-class-members/sort-class-members\": [\n      2,\n      {\n        \"order\": [\n          \"[static-properties]\",\n          \"[static-methods]\",\n          \"[properties]\",\n          \"[conventional-private-properties]\",\n          \"constructor\",\n          \"[methods]\",\n          \"[conventional-private-methods]\"\n        ],\n        \"accessorPairPositioning\": \"getThenSet\"\n      }\n    ],\n    \"lines-between-class-members\": \"off\",\n    \"@typescript-eslint/no-floating-promises\": \"error\",\n    \"@typescript-eslint/no-namespace\": \"off\",\n    \"react/jsx-filename-extension\": [0],\n    \"import/extensions\": [\n      \"error\",\n      \"ignorePackages\",\n      {\n        \"js\": \"never\",\n        \"mjs\": \"never\",\n        \"jsx\": \"never\",\n        \"ts\": \"never\",\n        \"tsx\": \"never\"\n      }\n    ]\n  },\n  \"overrides\": [\n    {\n      \"files\": [\"*.test.ts\", \"*.spec.ts\"],\n      \"rules\": {\n        \"no-await-in-loop\": \"off\",\n        \"@typescript-eslint/explicit-function-return-type\": \"off\",\n        \"no-restricted-syntax\": \"off\",\n        \"compat/compat\": \"off\",\n        \"no-new\": \"off\",\n        \"@typescript-eslint/no-empty-function\": \"off\",\n        \"@typescript-eslint/no-explicit-any\": \"off\",\n        \"@typescript-eslint/no-non-null-assertion\": \"off\",\n        \"@typescript-eslint/no-unused-expressions\": \"off\",\n        \"@typescript-eslint/naming-convention\": [\n          \"error\",\n          {\n            \"selector\": \"default\",\n            \"format\": [\"camelCase\", \"PascalCase\", \"UPPER_CASE\"],\n            \"leadingUnderscore\": \"allow\"\n          }\n        ]\n      }\n    }\n  ],\n  \"settings\": {\n    \"polyfills\": [\n      \"Array.from\",\n      \"Array.prototype.find\",\n      \"Array.prototype.includes\",\n      \"Symbol\",\n      \"Symbol.iterator\",\n      \"DOMTokenList\",\n      \"Object.assign\",\n      \"CustomEvent\",\n      \"Element.prototype.classList\",\n      \"Element.prototype.closest\",\n      \"Element.prototype.dataset\",\n      \"Element.prototype.replaceChildren\"\n    ],\n    \"import/resolver\": {\n      \"node\": {\n        \"extensions\": [\".js\", \".ts\"]\n      }\n    }\n  },\n  \"ignorePatterns\": [\"node_modules/*\", \"public/*\"]\n}\n"
  },
  {
    "path": ".git-blame-ignore-revs",
    "content": "# byte shaving (hoist semi-commonly variables, remove some low level low-usage functions)\n157a47a44a01e3ce4b54ad211b1756ff59985bef\n5bee41d7ff08e05442b232e3e552dcb6c703568d\ne9382df0ae63edfc7540f82f74cf969342c759c0\n\n# prettier config change\n00433d200d8cccc8b544fbc8f05d5e96bf8ccff7\n\n# misc linting cleanup\n00009d2effa8b41a6ce27ef8b06a35a04215aea6\n62b786d1f13d0934137a62909d3a37db0a3e927e\n5ad61841143508c9f91f0edd57f81f8b11066e0a\n84a61cad1ddab1e851c98efa619a2cd35af434c1\n33f573247e8badc9ee10defe326f13985342e09b\nb0199538a82d49de429f35546e412d14fc8bfeb9"
  },
  {
    "path": ".gitattributes",
    "content": "## GITATTRIBUTES FOR WEB PROJECTS\n#\n# These settings are for any web project.\n#\n# Details per file setting:\n#   text    These files should be normalized (i.e. convert CRLF to LF).\n#   binary  These files are binary and should be left untouched.\n#\n# Note that binary is a macro for -text -diff.\n######################################################################\n\n# Auto detect\n##   Handle line endings automatically for files detected as\n##   text and leave all files detected as binary untouched.\n##   This will handle all files NOT defined below.\n*                 text eol=lf\n\n# Source code\n*.css             text eol=lf\n*.html            text diff=html eol=lf\n*.js              text eol=lf\n*.json            text eol=lf\n*.scss            text diff=css eol=lf\n*.ts              text eol=lf\n\n# Documentation\n*.md              text eol=lf\n*.txt             text eol=lf\nAUTHORS           text eol=lf\nCHANGELOG         text eol=lf\nCHANGES           text eol=lf\nCONTRIBUTING      text eol=lf\nCOPYING           text eol=lf\ncopyright         text eol=lf\n*COPYRIGHT*       text eol=lf\nINSTALL           text eol=lf\nlicense           text eol=lf\nLICENSE           text eol=lf\nNEWS              text eol=lf\nreadme            text eol=lf\n*README*          text eol=lf\nTODO              text eol=lf\n\n# Linters\n.eslintrc         text eol=lf\n.stylelintrc      text eol=lf\n\n# Configs\n.babelrc          text eol=lf\n.browserslistrc   text eol=lf\n.editorconfig     text eol=lf\n.env              text eol=lf\n.gitattributes    text eol=lf\n.gitconfig        text eol=lf\npackage-lock.json text -diff eol=lf\n*.npmignore       text eol=lf\n*.yaml            text eol=lf\n*.yml             text eol=lf\nbrowserslist      text eol=lf\n\n# Graphics\n# SVG treated as an asset (binary) by default.\n*.svg             text eol=lf\n*.png             binary\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.md",
    "content": "---\nname: Bug report\nabout: Create a report to help us improve\ntitle: ''\nlabels: bug\nassignees: ''\n\n---\n\n**Describe the bug**\nA clear and concise description of what the bug is.\n\n**To Reproduce**\nUsing https://jsfiddle.net/ to create a minimal reproducible example.\n\nOtherwise\n\nSteps to reproduce the behavior:\n1. Go to '...'\n2. Click on '....'\n3. Scroll down to '....'\n4. See error\n\n**Expected behavior**\nA clear and concise description of what you expected to happen.\n\n**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n**Choices version and bundle**\n- Version: [e.g. v11.0.0 choices.min.js]\n\n**Desktop (please complete the following information):**\n - OS: [e.g. iOS]\n - Browser [e.g. chrome, safari]\n - Version [e.g. 22]\n\n**Smartphone (please complete the following information):**\n - Device: [e.g. iPhone6]\n - OS: [e.g. iOS8.1]\n - Browser [e.g. stock browser, safari]\n - Version [e.g. 22]\n\n**Additional context**\nAdd any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: feature request\nassignees: ''\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nA clear and concise description of any alternative solutions or features you've considered.\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/PULL_REQUEST_TEMPLATE.md",
    "content": "## Description\n\n<!--- Describe your changes in detail -->\n<!--- Why is this change required? What problem does it solve? -->\n<!--- If it fixes an open issue, please link to the issue here. -->\n\n## Screenshots (if appropriate)\n\n## Types of changes\n\n<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->\n\n- [ ] Chore (tooling change or documentation change)\n- [ ] Refactor (non-breaking change which maintains existing functionality)\n- [ ] Bug fix (non-breaking change which fixes an issue)\n- [ ] New feature (non-breaking change which adds functionality)\n- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)\n\n## Checklist\n\n<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->\n<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->\n\n- [ ] My code follows the code style of this project.\n- [ ] I have added new tests for the bug I fixed/the new feature I added.\n- [ ] I have modified existing tests for the bug I fixed/the new feature I added.\n- [ ] My change requires a change to the documentation.\n- [ ] I have updated the documentation accordingly.\n"
  },
  {
    "path": ".github/actions-scripts/polyfills-sync.cjs",
    "content": "const { readFileSync } = require('fs');\nconst path = require('path');\nconst assert = require('assert');\n\nconst readme = readFileSync(path.resolve(__dirname, '../../README.md'), 'utf8');\n\nconst polyfillsFromDocs = /^```polyfills\\s*\\n([^`]+)\\n^```/m\n  .exec(readme)[1]\n  .split('\\n')\n  .map(v => v.trim())\n  .sort();\n// @ts-ignore\nconst polyfillsFromSettings = require('../../.eslintrc.json').settings.polyfills.sort();\nassert.deepStrictEqual(polyfillsFromDocs, polyfillsFromSettings);\n"
  },
  {
    "path": ".github/release-drafter.yml",
    "content": "name-template: 'Draft (next release)'\ntag-template: 'v$NEXT_PATCH_VERSION'\nsort-direction: descending\nexclude-labels:\n  - 'skip-changelog'\n  - 'release'\ncategories:\n  - title: '🚨 Breaking changes'\n    labels:\n      - 'breaking change'\n  - title: '🚀 Features'\n    labels:\n      - 'feature'\n      - 'enhancement'\n  - title: '🐛 Bug Fixes'\n    labels:\n      - 'bugfix'\n  - title: '🔧 Maintenance'\n    labels:\n      - 'chore'\n      - 'housekeeping'\n      - 'refactor'\n      - 'documentation'\nchange-template: '- $TITLE @$AUTHOR (#$NUMBER)'\ntemplate: |\n  # Changes\n  $CHANGES\n  # Contributors\n  $CONTRIBUTORS\n"
  },
  {
    "path": ".github/workflows/browsers.yml",
    "content": "name: End-to-end tests (playwright)\non:\n  push:\n    branches: [ main ]\n    paths:\n      - 'src/**'\n      - 'test-e2e/**'\n      - 'package-lock.json'\n      - '.browserslistrc'\n      - 'babel.config.json'\n      - 'public/index.html'\n      - 'public/**/index.html'\n      - '.github/workflows/browsers.yml'\n      - 'playwright.config.ts'\n  pull_request:\n    paths:\n      - 'src/**'\n      - 'test-e2e/**'\n      - 'package-lock.json'\n      - '.browserslistrc'\n      - 'babel.config.json'\n      - 'public/index.html'\n      - 'public/**/index.html'\n      - '.github/workflows/browsers.yml'\n      - 'playwright.config.ts'\njobs:\n  test-e2e-playwright:\n    timeout-minutes: 60\n    strategy:\n      fail-fast: false\n      matrix:\n        os: [windows-latest, macos-latest, ubuntu-latest]\n        browser: [chromium, firefox, webkit]\n        exclude:\n          - os: windows-latest\n            browser: webkit\n          - os: windows-latest\n            browser: firefox\n          - os: macos-latest\n            browser: firefox\n    runs-on: ${{ matrix.os }}\n    steps:\n    - uses: actions/checkout@v4\n      with:\n        fetch-depth: 1\n\n    - uses: actions/setup-node@v4\n      with:\n        node-version: 24\n        cache: 'npm'\n\n    - name: Install dependencies\n      run: npm ci --no-audit\n    - name: Install Playwright Browsers\n      run: npx playwright install --with-deps\n    - run: npx playwright install-deps\n\n    - name: Run Playwright tests\n      run: npx playwright test --project=${{ matrix.browser }}\n\n    - uses: actions/upload-artifact@v4\n      name: Upload screenshots to GitHub Actions Artifacts\n      if: failure()\n      with:\n        name: screenshot-${{ matrix.os }}-${{ matrix.browser }}\n        path: test-results/**/*.png\n\n    - uses: actions/upload-artifact@v4\n      name: Upload blob report to GitHub Actions Artifacts\n      if: ${{ !cancelled() }}\n      with:\n        name: playwright-report-${{ matrix.os }}-${{ matrix.browser }}\n        path: playwright-report/\n        retention-days: 30"
  },
  {
    "path": ".github/workflows/bundlesize.yml",
    "content": "name: Bundle size checks\n\non:\n  push:\n    branches: [ main ]\n    paths:\n      - '.github/workflows/bundlesize.yml'\n      - 'src/scripts/**'\n      - 'src/styles/**'\n      - 'package-lock.json'\n      - '.browserslistrc'\n  pull_request:\n    paths:\n      - '.github/workflows/bundlesize.yml'\n      - 'src/scripts/**'\n      - 'src/styles/**'\n      - 'package-lock.json'\n      - '.browserslistrc'\n\njobs:\n  measure:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 1\n\n      - uses: actions/setup-node@v4\n        with:\n          node-version: 24\n          cache: 'npm'\n\n      - name: Install dependencies\n        run: npm ci --no-audit\n\n      - run: npm run build\n\n      # we don't need to build here, as even minized assets expected to be commited\n\n      - run: npm run bundlesize\n        env:\n          # token has expired, don't block the test\n          #CI: true\n          #BUNDLESIZE_GITHUB_TOKEN: ${{secrets.BUNDLESIZE_GITHUB_TOKEN}}\n          CI_REPO_NAME: ${{ github.event.repository.name }}\n          CI_REPO_OWNER: ${{ github.event.organization.login }}\n          CI_COMMIT_SHA: ${{ github.event.after }}\n          GIT_COMMIT: ${{ github.event.after }}\n          CI_BRANCH: ${{ github.head_ref }}\n          FORCE_COLOR: 2\n"
  },
  {
    "path": ".github/workflows/deploy-pages.yml",
    "content": "name: Deploy Pages\n\non:\n  release:\n    types: [published]\n  workflow_dispatch:\n\njobs:\n  deploy-gh-pages:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 1\n      - uses: actions/setup-node@v4\n        with:\n          node-version: 24\n      - name: Build\n        run: |\n          npm ci\n          npm run build\n          rm -rf public/test\n      - name: Deploy\n        uses: peaceiris/actions-gh-pages@v4\n        with:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          PUBLISH_BRANCH: gh-pages\n          PUBLISH_DIR: ./public\n"
  },
  {
    "path": ".github/workflows/deployment.yml",
    "content": "name: Publish to npm\n\non:\n  release:\n    types: [published]\n\npermissions:\n  id-token: write  # Required for OIDC\n  contents: read\n\njobs:\n  publish-npm:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 1\n      - uses: actions/setup-node@v4\n        with:\n          node-version: 24\n      - run: npm ci\n      - run: npm publish --provenance --access public\n"
  },
  {
    "path": ".github/workflows/lint.yml",
    "content": "name: Code linting\n\non:\n  push:\n    branches: [ main ]\n    paths:\n      - '.github/workflows/lint.yml'\n      - 'src/scripts/**'\n      - 'src/*.ts'\n      - 'src/styles/**'\n      - 'test/**'\n      - 'test-e2e/**'\n      - 'package-lock.json'\n      - '.browserslistrc'\n      - '.eslintrc.json'\n      - '.editorconfig'\n      - '.prettierrc.json'\n      - '.stylelintrc.json'\n  pull_request:\n    paths:\n      - '.github/workflows/lint.yml'\n      - 'src/scripts/**'\n      - 'src/*.ts'\n      - 'src/styles/**'\n      - 'test/**'\n      - 'test-e2e/**'\n      - 'package-lock.json'\n      - '.browserslistrc'\n      - '.eslintrc.json'\n      - '.editorconfig'\n      - '.prettierrc.json'\n      - '.stylelintrc.json'\n\njobs:\n  lint:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 1\n\n      - uses: actions/setup-node@v4\n        with:\n          node-version: 24\n          cache: 'npm'\n\n      - name: Install dependencies\n        run: npm ci --no-audit\n      - name: run eslint\n        run: npm run lint:js\n\n      ## Can't use same eslint config for TypeScript and JavaScript\n      ## TypeScript rules cause rule definition not found errors\n      ## Can be re-enabled if this is resolved: https://github.com/eslint/eslint/issues/14851\n      # - name: Lint JS bundle\n      #   run: |\n      #     npm run js:build\n      #     npx eslint --no-ignore ./public/assets/scripts/*.js\n\n      - name: run stylelint\n        run: npm run lint:scss"
  },
  {
    "path": ".github/workflows/polyfills-sync.yml",
    "content": "name: Polyfills documentation\n\non:\n  pull_request:\n    paths:\n      - 'README.md'\n      - '.browserslistrc'\n      - '.eslintrc.json'\n\njobs:\n  sync:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 1\n\n      - uses: actions/setup-node@v4\n        with:\n          node-version: 24\n\n      - name: Check Polyfills documentation and settings sync\n        run: node .github/actions-scripts/polyfills-sync.cjs\n"
  },
  {
    "path": ".github/workflows/release-drafter.yml",
    "content": "name: Release drafter\n\non:\n  push:\n    branches: [ main ]\n\njobs:\n  update-draft-release:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: release-drafter/release-drafter@v5\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".github/workflows/unit-tests.yml",
    "content": "name: Unit tests\n\non:\n  push:\n    branches: [ main ]\n    paths:\n      - '.github/workflows/unit-tests.yml'\n      - 'src/scripts/**'\n      - 'src/*.ts'\n      - 'test/**'\n      - 'package-lock.json'\n      - '.browserslistrc'\n      - 'babel.config.json'\n      - 'vitest.config.ts'\n  pull_request:\n    paths:\n      - '.github/workflows/unit-tests.yml'\n      - 'src/scripts/**'\n      - 'src/*.ts'\n      - 'test/**'\n      - 'package-lock.json'\n      - '.browserslistrc'\n      - 'babel.config.json'\n      - 'vitest.config.ts'\n\njobs:\n  test-unit:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          fetch-depth: 1\n\n      - uses: actions/setup-node@v4\n        with:\n          node-version: 24\n          cache: 'npm'\n\n      - name: Install dependencies\n        run: npm ci --no-audit\n\n      - run: npm run build\n\n      - run: npm run test:unit:coverage\n        env:\n          FORCE_COLOR: 2\n\n      - name: Upload coverage to Codecov\n        run: bash <(curl -s https://codecov.io/bash)\n          -f ./coverage/lcov.info\n          -B ${{ github.head_ref }}\n          -C ${{ github.sha }}\n          -Z || echo 'Codecov upload failed'\n        env:\n          CI: true\n          GITLAB_CI: true # pretend we are GitLab CI, while Codecov adding support for Github Actions\n          CODECOV_ENV: github-action\n          CODECOV_TOKEN: ${{secrets.CODECOV_TOKEN}}\n"
  },
  {
    "path": ".gitignore",
    "content": "node_modules\nnpm-debug.log\n.DS_Store\n.idea\n.rollup.cache\ntsconfig.tsbuildinfo\n.npmrc\n.run\n\n# Test\ntests/reports\ntests/results\n.nyc_output\ncoverage\n/test-results/\n/playwright-report/\n/blob-report/\n/playwright/.cache/\n"
  },
  {
    "path": ".nvmrc",
    "content": "v22.17.0"
  },
  {
    "path": ".prettierrc.json",
    "content": "{\n  \"printWidth\": 120,\n  \"singleQuote\": true,\n  \"trailingComma\": \"all\",\n  \"endOfLine\": \"lf\",\n  \"overrides\": [\n    {\n      \"files\": [\"*.svg\"],\n      \"options\": {\n        \"parser\": \"html\",\n        \"htmlWhitespaceSensitivity\": \"ignore\"\n      }\n    },\n    {\n      \"files\": [\"public/*.html\"],\n      \"options\": {\n        \"trailingComma\": \"es5\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": ".stylelintrc.json",
    "content": "{\n  \"extends\": \"stylelint-config-standard-scss\",\n  \"rules\": {\n    \"media-feature-range-notation\": null,\n    \"declaration-block-no-redundant-longhand-properties\": null\n  }\n}"
  },
  {
    "path": ".vscode/extensions.json",
    "content": "{\n  // See http://go.microsoft.com/fwlink/?LinkId=827846\n  // for the documentation about the extensions.json format\n  \"recommendations\": [\n    // we enforce ESLint rules, so, recommend extension\n    \"dbaeumer.vscode-eslint\",\n    // we use prettier, so, recommend extension\n    \"esbenp.prettier-vscode\",\n    // we are on GitHub, so, recommend extension\n    \"github.vscode-pull-request-github\",\n    // needed for our configured debug configuration with Chrome\n    \"msjsdiag.debugger-for-chrome\"\n  ]\n}\n"
  },
  {
    "path": ".vscode/launch.json",
    "content": "{\n  \"version\": \"0.2.0\",\n  \"configurations\": [\n    {\n      \"type\": \"chrome\",\n      \"request\": \"launch\",\n      \"name\": \"Launch Chrome\",\n      \"preLaunchTask\": \"buildAndWatch\",\n      \"url\": \"http://localhost:3001\",\n      \"webRoot\": \"${workspaceFolder}\",\n      \"sourceMapPathOverrides\": {\n        \"webpack://Choices/*\": \"${workspaceFolder}/*\"\n      }\n    },\n  ]\n}\n"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n  \"eslint.enable\": true,\n  // prevent watch task failures on lint errors\n  \"eslint.autoFixOnSave\": true,\n  // switch off default VSCode formatting rules\n  \"javascript.format.enable\": false,\n  // Javascript prettier runs via ESLint\n  \"prettier.disableLanguages\": [\"javascript\"],\n  \"[json]\": {\n    \"editor.defaultFormatter\": \"esbenp.prettier-vscode\"\n  },\n  \"[html]\": {\n    \"editor.defaultFormatter\": \"esbenp.prettier-vscode\"\n  },\n  \"[scss]\": {\n    \"editor.defaultFormatter\": \"esbenp.prettier-vscode\"\n  },\n  \"[javascript]\": {\n    \"editor.formatOnSave\": false\n  },\n  \"search.exclude\": {\n    \"**/node_modules\": true,\n    \"public/assets\": true,\n    \"**/coverage\": true\n  },\n  // for Windows collaborators\n  \"files.eol\": \"\\n\",\n  \"files.encoding\": \"utf8\",\n  // associations for some files this project is using\n  \"files.associations\": {\n    \".browserslistrc\": \"gitignore\",\n    \".npmrc\": \"ini\"\n  },\n  // We use NPM as package manager\n  \"npm.packageManager\": \"npm\",\n  \"npm.autoDetect\": \"on\",\n  \"npm.fetchOnlinePackageInfo\": true,\n  \"eslint.packageManager\": \"npm\",\n  \"json.schemas\": [\n    // Prettier config\n    {\n      \"fileMatch\": [\".prettierrc.json\"],\n      \"url\": \"http://json.schemastore.org/prettierrc\"\n    }\n  ],\n  \"editor.codeActionsOnSave\": {\n    \"source.fixAll.eslint\": true\n  },\n  \"stylelint.validate\": [\n    \"css\",\n    \"less\",\n    \"postcss\",\n    \"scss\"\n  ]\n}\n"
  },
  {
    "path": ".vscode/tasks.json",
    "content": "{\n  // See https://go.microsoft.com/fwlink/?LinkId=733558\n  // for the documentation about the tasks.json format\n  \"version\": \"2.0.0\",\n  \"tasks\": [\n    {\n      \"type\": \"npm\",\n      \"label\": \"buildAndWatch\",\n      \"script\": \"js:watch\",\n      \"group\": {\n        \"kind\": \"build\",\n        \"isDefault\": true\n      },\n      \"isBackground\": true,\n      \"presentation\": {\n        \"echo\": true,\n        \"reveal\": \"always\",\n        \"focus\": false,\n        \"panel\": \"dedicated\",\n        \"showReuseMessage\": true,\n        \"clear\": false\n      },\n      \"problemMatcher\": [\n        \"$eslint-stylish\",\n        {\n          \"owner\": \"webpack\",\n          \"fileLocation\": \"absolute\",\n          \"pattern\": [\n            {\n              \"regexp\": \"^Module build failed \\\\(from (\\\\.+)\\\\)\",\n              \"file\": 1,\n              \"line\": 2,\n              \"column\": 3\n            },\n            {\n              \"regexp\": \"\\\\s*TS\\\\d+:\\\\s*(.*)\",\n              \"message\": 1\n            }\n          ],\n          \"severity\": \"error\",\n          \"source\": \"webpack\",\n          \"background\": {\n            \"activeOnStart\": true,\n            \"beginsPattern\": \"^Listening at\",\n            \"endsPattern\": \"Compiled successfully\\\\.\"\n          }\n        }\n      ]\n    },\n    {\n      \"type\": \"npm\",\n      \"script\": \"css:build\",\n      \"group\": \"build\",\n      \"problemMatcher\": [\"$node-sass\"]\n    },\n    {\n      \"type\": \"npm\",\n      \"script\": \"lint\",\n      \"problemMatcher\": [\"$eslint-stylish\"]\n    },\n    {\n      \"type\": \"npm\",\n      \"script\": \"build\",\n      \"group\": \"build\"\n    },\n    {\n      \"type\": \"npm\",\n      \"script\": \"test\",\n      \"group\": \"test\"\n    },\n    {\n      \"type\": \"npm\",\n      \"script\": \"test:e2e\",\n      \"group\": \"test\"\n    },\n    {\n      \"type\": \"npm\",\n      \"script\": \"test:unit\",\n      \"group\": \"test\"\n    },\n  ]\n}\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\n## [11.2.0] (2026-01-05)\n\n### Features\n- Add `searchRenderSelectedChoices` configuration option to control whether selected choices appear in search results for select-multiple inputs. Defaults to `true` (backward compatible behavior). Set to `false` to hide selected choices from search results.\n- Add support for `required` html attribute [#1332](https://github.com/Choices-js/Choices/pull/1332)\n   - Note; This feature requires updating any css targeting the `.choices [hidden]` selector\n- Improve UX on the select dropdown [#1361](https://github.com/Choices-js/Choices/pull/1361)\n- Add `searchDisabledChoices` configuration option to allow disabled choices to appear in search results [#1357](https://github.com/Choices-js/Choices/pull/1357)\n- Add additional SCSS variables [#1304](https://github.com/Choices-js/Choices/pull/1304)\n- Add CSS custom properties support (+ dark mode for the intro page) (#1335](https://github.com/Choices-js/Choices/pull/1335)\n- Soften constraints on remove buttons [#1338](https://github.com/Choices-js/Choices/pull/1338)\n\n### Bugfixes\n- Fix data-label-description from source html was not treated as trusted [#1365](https://github.com/Choices-js/Choices/pull/1365)\n- Fix kmp search not returning results as expected [#1364](https://github.com/Choices-js/Choices/pull/1364)\n- Fix selected choice was not reliably highlighted when opening the dropdown [#1339](https://github.com/Choices-js/Choices/pull/1339)\n- Define `[aria-selected]` for selectable choices per WAI-ARIA 1.2 spec, and avoid triple state with aria-selected [#1330](https://github.com/Choices-js/Choices/pull/1330)\n- Fix `appendGroupInSearch` option was non-functional [#1324](https://github.com/Choices-js/Choices/pull/1324)\n- When resolving the remove item/label/icon, add a 3rd argument item argument. Update default remove item label to use this (Fixes #1296) [#1323](https://github.com/Choices-js/Choices/pull/1323)\n- Fix `searchResultLimit` could not be set to `-1` when `renderChoiceLimit` was set [#1322](https://github.com/Choices-js/Choices/pull/1322)\n- Fix dropdown would stick closed when a search loses focus [#1308](https://github.com/Choices-js/Choices/pull/1308)\n- Fix `searchEnabled` being disabled for `select-multiple` did not work [#1366](https://github.com/Choices-js/Choices/pull/1366)\n\n### Chore\n- Update callback argument documentation\n- Update development dependencies to fix npm install warning\n\n## [11.1.0] (2025-03-14)\n\n### Features\n- Support `<option>` label attribute [#1289](https://github.com/Choices-js/Choices/pull/1289)\n- Add KMP search algorithm (gated by build flag) [#1229](https://github.com/Choices-js/Choices/issue/1229) [#1277](https://github.com/Choices-js/Choices/pull/1277)\n\n### Bug Fixes\n- Remove `role=\"textbox\"` from search input, per a11y practices. [#941](https://github.com/Choices-js/Choices/issues/941) @mlinnetz ([#1285](https://github.com/Choices-js/Choices/issues/1285))\n\n## [11.0.6] (2025-02-27)\n\n### Breaking changes\n- Changes to `setChoices` & `clearChoices` adjust how the selection and new choices combine when using `replaceChoices: true` is used to better match v10 and v11.0.3 behavior.\n  - To remove duplication, consider `duplicateItemsAllowed: false` to be set, or use the new 6th argument `replaceItems:true`\n\n### Bug Fixes\n- Fix `setChoices` & `clearChoices` related regressions @Xon ([#1278](https://github.com/Choices-js/Choices/issues/1278])) [#1283](https://github.com/Choices-js/Choices/issues/1283)\n- Revert \"Do not preventDefault on item to support dragging\" [#1266](https://github.com/Choices-js/Choices/issues/1266) @Xon ([#1282](https://github.com/Choices-js/Choices/issues/1282))\n\n### Chore\n- Add e2e test for dropdown behavior on item mouse down/click\n- Add e2e test for serveral `setChoices`/`clearChoices` actions\n\n## [11.0.5] (2025-02-26)\n\n### Bug Fixes\n- Fix regression when calling setChoices [#1278](https://github.com/Choices-js/Choices/issues/1278)\n\n## [11.0.4] (2025-02-23)\n\n### Features\n- Do not preventDefault on item to support dragging [#417](https://github.com/Choices-js/Choices/issues/417) [#1094](https://github.com/Choices-js/Choices/issues/1094) [#920](https://github.com/Choices-js/Choices/issues/920)\n\n### Bug Fixes (from 11.0.0)\n- Fix performance regression when calling setChoices [#1275](https://github.com/Choices-js/Choices/issues/1275)\n* Fix `renderSelectedChoices` option when all choices are selected [#1274](https://github.com/Choices-js/Choices/issues/1274)\n* Fix v11 regression for disabled placeholder option handling [#1203](https://github.com/Choices-js/Choices/issues/1203)\n* Fix v11 regression where `clearChoices` (and `setChoices` with `replaceChoices:true`) did not remove selected items when preserving placeholders [#1261](https://github.com/Choices-js/Choices/issues/1261)\n* Fix v11 regression where `duplicateItemsAllowed` option did not work with `select-one`/`select-multiple` [#1271](https://github.com/Choices-js/Choices/issues/1271)\n* Fix: Reached maximum item limit notice is not cleared after removing selections [#1249](https://github.com/Choices-js/Choices/issues/1249)\n* Fix: Disabled options are not visible [#1257](https://github.com/Choices-js/Choices/issues/1257) [#1269](https://github.com/Choices-js/Choices/issues/1257)\n* Fix: Clear button reverses items order [#1251](https://github.com/Choices-js/Choices/issues/1251)\n* Fix `tab` => direction keys handling with disabled search [#1260](https://github.com/Choices-js/Choices/issues/1260)\n* Improve cjs compatibility by removing pinned \"module\" type in package.json [#1250](https://github.com/Choices-js/Choices/issues/1250)\n\n## [11.0.3] (2024-12-22)\n\n### Bug Fixes (from 11.0.0)\n* Fix input text - method setValue didn't work [#1207](https://github.com/Choices-js/Choices/issues/1207)\n* Fix `tab` and `esc` keys handling [#1234](https://github.com/Choices-js/Choices/issues/1234) [#1209](https://github.com/Choices-js/Choices/issues/1209)\n* Fix Notice for max item limit is removed permanently if you keep typing [#1201](https://github.com/Choices-js/Choices/issues/1201)\n* Fix search was not stopped when leaving focus with esc key [#1240](https://github.com/Choices-js/Choices/issues/1240)\n* Fix single-select mode disabling search when `tab` => arrow keys are pressed [#1230](https://github.com/Choices-js/Choices/issues/1230)\n* Fix HTML comments were copied from backing `<option>` and were rendered as text [#1231](https://github.com/Choices-js/Choices/issues/1231)\n\n## [11.0.2] (2024-09-05)\n\n### Features (from 11.0.0)\n* Pass `getClassNames` as the 3rd argument to `callbackOnCreateTemplates` callback\n* `duplicateItemsAllowed` option is now respected by `setChoices()` method [#855](https://github.com/Choices-js/Choices/issues/855)\n\n### Bug Fixes (from 11.0.0)\n* Fix choice disable state wasn't considered when showing the \"no choices to choose from\" notice\n* Fix regression where webpack doesn't permit importing scss/css @tagliala [#1193](https://github.com/Choices-js/Choices/issues/1193)\n* Fix regression \"no choices to choose from\"/\"no results found\" notice did not reliably trigger. [#1185](https://github.com/Choices-js/Choices/issues/1185) [#1191](https://github.com/Choices-js/Choices/issues/1191)\n* Fix regression of `UnhighlightItem` event not firing [#1173](https://github.com/Choices-js/Choices/issues/1173)\n* Fix `clearChoices()` would remove items, and clear the search flag.\n* Fixes for opt-group handling/rendering\n* Fix `removeChoice()` did not properly remove a choice which was part of a group\n\n### Chore\n* Add e2e tests for \"no choices\" behavior to match v10\n\n## [11.0.1] (2024-08-30)\n\n### Bug Fixes (from 11.0.0)\n* Fix the rendered item list was not cleared when `clearStore` was called. This impacted the on-form-reset and `refresh` features.\n\n### Chore\n* Add e2e test for 'form reset' and 'on paste & search'.\n* Cleanup adding classes to generated elements.\n\n## [11.0.0] (2024-08-28)\n\n### ⚠ BREAKING CHANGES\n* Update polyfills to include `Element.prototype.replaceChildren`\n* Number of internal APIs have changed\n\n### Bug Fixes (from 10.2.0)\n* Reduce work done for `unhighlightAll` during on-click handler (batching in v11.0.0-rc8 would also have helped) [#522](https://github.com/Choices-js/Choices/issues/522) [#599](https://github.com/Choices-js/Choices/issues/599)\n* Improve performance when rendering very large number of items and choices. Stuttering when stopping searching or selecting an item still happens depending on device and number of choices.\n\n## [11.0.0-rc8] (2024-08-23)\n\n### ⚠ BREAKING CHANGES\n* Trigger a search event (with empty value and 0 resultCount) when search stops\n\n### Features\n* `searchResultLimit` can be set to `-1` for no limit of search results to display.\n\n### Bug Fixes (from 10.2.0)\n* Fix edge case where aria-label could be added twice\n* Fix the page scrolls when you press 'space' on a single select input #1103\n* Update typescript definition for `removeActiveItems` to explicitly mark `excludedId` as optional #1116\n\n### Chore\n* Reduce the number of loops over choices when rendering search results, results in more compact code.\n* Byte shave bundle sizes down\n\n## [11.0.0-rc7] (2024-08-19)\n\n### ⚠ BREAKING CHANGES\n* Improve consistency of the `choice` event firing. `choice` event now occurs after the `addItem` event\n* `enter` key now consistently opens/closes the dropdown instead of the behavior varying depending on backing element or internal state of the highlighted choice\n\n### Features\n* Add `closeDropdownOnSelect` option, controls how the dropdown is close after selection is made. [#636](https://github.com/Choices-js/Choices/issues/636) [#973](https://github.com/Choices-js/Choices/issues/873) [#1012](https://github.com/Choices-js/Choices/issues/1012)\n* Allow choices.js to be imported on nodejs, useful for tests and also server side rendering. As windows.document is by default not defined, the default template rendering will not function. The `callbackOnCreateTemplates` callback must be used. [#861](https://github.com/Choices-js/Choices/issues/861)\n\n### Bug Fixes (from 10.2.0)\n* Improve various `[aria-*]` attribute handling for better lighthouse accessibility scores [#1169](https://github.com/Choices-js/Choices/issues/1169)\n* Improve contrast on default CSS by darkening primary item selection color [#924](https://github.com/Choices-js/Choices/issues/924)\n\n### Bug Fixes (from 11.0.0RC6)\n* Fix destroy&init of `choices.js` would lost track of data from the backing `<input>`/`<select>`\n* Update e2e tests\n\n### Bug Fixes (from 11.0.0RC1)\n* Fix various `select-one` bugs related to how `<select>` initializes and selected values do not match the configured `choices.js`\n* Fix legacy `placeholder` attribute support for `select-one`\n* Fix `data-value` attribute on choices may not be correctly rendered into html\n\n### Chore\n* Switch e2e tests from `puppeteer`/`selenium`/`cypress` to `playwright`\n* Restructure end-to-end tests so html/script blocks are co-located to improve debugability\n* Enable `@typescript-eslint/explicit-function-return-type` eslint rule\n\n## [11.0.0-rc6] (2024-08-12)\n\n### ⚠ BREAKING CHANGES\n* Mutation APIs `setChoiceByValue`/`setChoices`/`setValue` now throw an error if the Choices instance was not initialized or multiple choices instances where initialized on the same element. Prevents bad internal states from triggering unexpected errors [#1129](https://github.com/Choices-js/Choices/issues/1129)\n\n### Features\n* Improve performance of search/filtering with large number of choices.\n\n### Bug Fixes (from 10.2.0)\n* Fix Choices does not accept an element from an iframe [#1057](https://github.com/Choices-js/Choices/issues/1057)\n* Fix Choices was not disable in a `<fieldset disabled>` [#1132](https://github.com/Choices-js/Choices/issues/1132)\n* Fix `silent` option does not silence warnings about unknown options [#1119](https://github.com/Choices-js/Choices/issues/1119)\n* Fix documentation that suggests duplicateItemsAllowed works with select-multiple, when it only works for text. [#1123](https://github.com/Choices-js/Choices/issues/1123)\n* Fix quadratic algorithm complexity (aka O(N^2) ) when filtering/search choices.\n* Fix search results could be unexpectedly unstable, and that `fuseOptions.sortFn` was effectively ignored [#1106](https://github.com/Choices-js/Choices/issues/1106)\n\n### Bug Fixes (from 11.0.0RC1)\n* Fix possible empty `aria-label` generation on remove item button\n* Fix `clearChoices()` did not remove the actual selection options\n\n## [11.0.0-rc5] (2024-08-08)\n\n### ⚠ BREAKING CHANGES\n* Update to using Fuse.js v7.0.0\n* Update choices.js package to be an ES module, and use '[subpath exports](https://nodejs.org/api/packages.html#subpath-exports)' to expose multiple versions (UMD, CJS or MTS bundles).\n* Provide \"fuse full\" (default `choices.js`, ~20.36KB), or \"fuse basic\" (`choices.search-basic.js` ~19.31KB) or \"prefix filter\" (`choices.search-filter.js` ~15.27KB) based on how much Fuse.js is included.\n\n### Bug Fixes (from 10.2.0)\n* Fix `select-one` placeholder could ignore the non-option placeholder configuration\n* Remove typescript types for tests from distribution\n\n### Chore\n* Reduce bundle size from ~24KB to ~20.36KB\n* Switch bundler from `webpack` to `rollup`\n* Switch test framework from `mocha` to `vitest`\n\n### Bug Fixes (from 11.0.0RC4)\n* Fix `aria-describedby` was being assigned when it shouldn't be\n* Fix check to ensure search was fully enabled for multiple select mode, as this functionality is hard-coded enabled elsewhere in the code base.\n\n## [11.0.0 RC3] (2024-08-04)\n\n### ⚠ BREAKING CHANGES\n* For `select-one` and `select-multiple`, the placeholder value is pulled from `config.placeholderValue=\"...\"` or `<select data-placeholder=\"...\">` before attempting to extract a placeholder from the options list. [#912](https://github.com/Choices-js/Choices/issues/912) [#567](https://github.com/Choices-js/Choices/issues/567) [#843](https://github.com/Choices-js/Choices/issues/843)\n\n### Bug Fixes (from 10.2.0)\n* Fix search did not trigger to copy&paste events [#860](https://github.com/Choices-js/Choices/issues/860) [#174](https://github.com/Choices-js/Choices/issues/174)\n\n### Chore\n* Update defaults for classnames to be arrays instead of strings\n\n### Bug Fixes (from 11.0.0 RC1)\n* Fix `noResults`/`noChoices` classes could not be set to a list of classes\n* Fix failing to add an item would close the dropdown\n* Fix invalid css selectors being generated for configurable css class-names with multiple css classes for an element\n* Fix \"Press Enter to add...\" would not render if the dropdown had partially matching search results\n* Fix render limit would allow `select-one` to select multiple items\n\n## [11.0.0 RC2] (2024-08-03)\n\n### Bug Fixes (from 10.2.0)\n* Avoid pushing a search to fuse.js which is just additional whitespace to the existing search term\n\n### Bug Fixes (from 11.0.0 RC1)\n* Fix error when using backspace key after adding an item and then removing it\n* Fix adding items for select boxes would not give the max item messages reliably\n* Fix `destroy()`/`init()` would not load choices from the underlying `<select>` as expected\n* Fix adding user provided choices for `select-one` would not remove the existing item and result in a select-one with multiple items set.\n\n### Chore\n* Remove unused code\n* Use constant enum instead of repeating strings and type information\n* For test html pages, prevent a failing `fetch()` from breaking the rest of the examples\n* Tweak `_render()` loop to avoid duplicating has-changed checks\n\n## [11.0.0 RC1] (2024-08-02)\n\n### ⚠ BREAKING CHANGES\n\n* `allowHtml` now defaults to false.\n* HTML escaping of choice/item labels should no longer double escape depending on allowHTML mode.\n* Templates/text functions now escape `'` characters for display.\n* `addItemText`/`uniqueItemText`/`customAddItemText` are now called with the `value` argument already escaped.\n* Typescript classes for input data vs internal working data have been adjusted resulting in the `Choice`/`Group`/`Item` typescript classes have been renamed, and aliases left as required.\n\n### Features\n\n* `config.classNames` now accept arrays to support multiple classes. [#1121](https://github.com/Choices-js/Choices/issues/1121) [#1074](https://github.com/Choices-js/Choices/issues/1074) [#907](https://github.com/Choices-js/Choices/issues/907) [#832](https://github.com/Choices-js/Choices/issues/832)\n* The original option list for the select is not destroyed, and all loaded choices are serialised to HTML for better compatibility with external javascript. [#1053](https://github.com/Choices-js/Choices/issues/1053) [#1023](https://github.com/Choices-js/Choices/issues/1023)\n* New `singleModeForMultiSelect` feature to treat a `select-single` as if it was a `select-multiple` with a max item count of `1`, and still auto-close the dropdown and swap the active item on selection. [#1136](https://github.com/Choices-js/Choices/issues/1136) [#904](https://github.com/Choices-js/Choices/issues/904)\n* `Remove item text` can be localized.\n* Allow user-created choices for selects. [#1117](https://github.com/Choices-js/Choices/issues/1117) [#1114](https://github.com/Choices-js/Choices/issues/1114)\n    * User input is escaped by default. At the risk of XSS attacks this can be disabled by `allowHtmlUserInput`.\n* Render options without a group even if groups are present. [#615](https://github.com/Choices-js/Choices/issues/615) [#1110](https://github.com/Choices-js/Choices/issues/1110)\n* Read `data-label-class`/`data-label-description` from `<option>` HTML to drive adding a per-choice CSS label and description text when `allowHtml: false`.\n* Add `removeItemButtonAlignLeft` option, to control if the remove item button is at the start or the end of the item.\n* Add `removeChoice` method. Removes the choice from the `choices.js` object and any backing `<option>` HTML element\n* Add `refresh` method. Reloads choices from the backing `<select>`s options.\n* Improve rendering performance by batching changes.\n* `escapeForTemplate` function is passed to the 2nd method of the `callbackOnCreateTemplates` callback.\n* When `allowHtml` is false, default templates now render escaped html to `innerHtml` writing to `innerText`.\n    * This provides consistent rendering performance as `innerText` is quirky and slower than escaped html into `innerHtml`\n* Shadow DOM support [#938](https://github.com/Choices-js/Choices/pull/938)\n\n### Bug Fixes\n\n* Replace malicious polyfill with cdnjs. [#1161](https://github.com/Choices-js/Choices/issues/1161)\n* Maintain groups in search mode. [#1152](https://github.com/Choices-js/Choices/issues/1152)\n* Fix various \"first press\" bugs on single select dropdowns. [#1104](https://github.com/Choices-js/Choices/issues/1104)\n* Fix 'esc' would close the dropdown and also apply to the container resulting in an overlay/modal unexpectedly closing. [#1039](https://github.com/Choices-js/Choices/issues/1039)\n* Fix form reset would clear the choices list, but not clear the search bar. [#1023](https://github.com/Choices-js/Choices/issues/1023)\n* Fix options would be disabled when choices.js was intialized on a disabled `<select>` element. [#1025](https://github.com/Choices-js/Choices/issues/1025)\n* Fix a `search_term` element to appear in form submit data. [#1049](https://github.com/Choices-js/Choices/issues/1049)\n* Fix 'remove item' button would trigger the change event twice due to placeholder value being used (match html single-select). [#892](https://github.com/Choices-js/Choices/issues/892)\n* Fix optgroups are not preserved when Choices is destroyed [#1055](https://github.com/Choices-js/Choices/issues/1055)\n* Fix placeholder config option would be ignored for select boxes which have blank entries.\n* Fix `data-custom-properties` attribute did not serialize to created elements as a json blob as expected. [#840](https://github.com/Choices-js/Choices/issues/840) [#1155](https://github.com/Choices-js/Choices/issues/1155) [#543](https://github.com/Choices-js/Choices/issues/543)\n* Fix multi-select did not correctly resizing when a select option is selected on choices.js initialization.\n* Fix clearInput function did not clear the last search.\n* Fix `addItemFilter` would allow empty strings as input to be added for items.\n* Fix various issues with double escaping when displaying items/choices depending on allowHTML mode.\n* Fix `aria-label` for placeholders was set to the string `null`\n* Fix `searchEnable` flag was not respected for `select-multiple` [#1042](https://github.com/Choices-js/Choices/issues/1042)\n* Fix poor error message when Choices is passed a string selector which fails to find the element for Choices to attach to.\n\n### Chore\n* Remove `deepMerge` dependency.\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.\n\n## Our Standards\n\nExamples of behavior that contributes to creating a positive environment include:\n\n* Using welcoming and inclusive language\n* Being respectful of differing viewpoints and experiences\n* Gracefully accepting constructive criticism\n* Focusing on what is best for the community\n* Showing empathy towards other community members\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery and unwelcome sexual attention or advances\n* Trolling, insulting/derogatory comments, and personal or political attacks\n* Public or private harassment\n* Publishing others' private information, such as a physical or electronic address, without explicit permission\n* Other conduct which could reasonably be considered inappropriate in a professional setting\n\n## Our Responsibilities\n\nProject maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.\n\nProject maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.\n\n## Scope\n\nThis Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.\n\n## Enforcement\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at josh@joshuajohnson.co.uk. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.\n\nProject maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.\n\n## Attribution\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]\n\n[homepage]: http://contributor-covenant.org\n[version]: http://contributor-covenant.org/version/1/4/\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributions\nIn lieu of a formal styleguide, take care to maintain the existing coding style ensuring there are no linting errors. Add unit tests for any new or changed functionality. Lint and test your code using the npm scripts below:\n\n### Minified code\nFor compatibility, `new` and `get` must be pure (side effect free).\n\n### NPM tasks\n| Task                      | Usage                                                        |\n|---------------------------|--------------------------------------------------------------|\n| `npm run start`           | Fire up local server for development                         |\n| `npm run test:unit`       | Run sequence of tests once                                   |\n| `npm run test:unit:watch` | Fire up test server and re-test on file change               |\n| `npm run test:e2e`        | Run sequence of e2e tests (with local server)                |\n| `npm run test`            | Run both unit and e2e tests                                  |\n| `npm run playwright:gui`  | Run Playwright e2e tests (GUI)                               |\n| `npm run playwright:cli`  | Run Playwright e2e tests (CLI)                               |\n| `npm run js:build`        | Compile Choices to an uglified JavaScript file               |\n| `npm run css:watch`       | Watch SCSS files for changes. On a change, run build process |\n| `npm run css:build`       | Compile, minify and prefix SCSS files to CSS                 |\n\n## Passing environmental arguments to rollup\n\nUse `--` followed by normal rollup `--environment` arguments. The last one overrides any previous ones with the same name\n\nAn example of changing what js:watch will bind to:\n```\nnpm run js:watch -- --environment WATCH_HOST:0.0.0.0\n```\n\n## Build flags\n\nThe following build flags are supported via environment variables:\n\n### CHOICES_SEARCH_FUSE\n**Values:**: **\"full\" / \"basic\" / \"null\" **\n**Usage:** The level of integration with fuse. `full` is the entire fuse.js build, `basic` is fuse.js with just standard fuzzy searching. `null` is a basic prefix string search with no fuse.js\n**Example**:\n```\nnpm run js:watch -- --environment CHOICES_SEARCH_FUSE:basic\n```\n\n### CHOICES_SEARCH_KMP\n**Values:**: **\"1\" / \"0\" **\n**Usage:** High performance `indexOf`-like search algorithm.\n**Example**:\n```\nnpm run js:watch -- --environment CHOICES_SEARCH_KMP:1\n```\n\n### CHOICES_CAN_USE_DOM\n**Values:**: **\"1\" / \"0\" **\n**Usage:** Indicates if DOM methods are supported in the global namespace. Useful if importing into DOM or the e2e tests without a DOM implementation available.\n**Example**:\n```\nnpm run js:watch -- --environment CHOICES_CAN_USE_DOM:1\n```\n\n## Pull requests\nWhen submitting a pull request that resolves a bug, feel free to use the following template:\n\n```md\n## This is the problem:\n\n## Steps to reproduce:\n\n## This is my solution:\n```\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2016 Josh Johnson\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Choices.js [![Actions Status](https://github.com/Choices-js/Choices/actions/workflows/unit-tests.yml/badge.svg)](https://github.com/Choices-js/Choices/actions) [![Actions Status](https://github.com/Choices-js/Choices/actions/workflows/bundlesize.yml/badge.svg)](https://github.com/Choices-js/Choices/actions) [![npm](https://img.shields.io/npm/v/choices.js.svg)](https://www.npmjs.com/package/choices.js)\n\nA vanilla, lightweight (~20kb gzipped 🎉), configurable select box/text input plugin. Similar to Select2 and Selectize but without the jQuery dependency.\n\n[Demo](https://choices-js.github.io/Choices/)\n\n## TL;DR\n\n- Lightweight\n- No jQuery dependency\n- Configurable sorting\n- Flexible styling\n- Fast search/filtering\n- Clean API\n- Right-to-left support\n- Custom templates\n\n---\n\n### Interested in writing your own ES6 JavaScript plugins? Check out [ES6.io](https://ES6.io/friend/JOHNSON) for great tutorials! 💪🏼\n\n### Sponsored by:\n\n<p align=\"center\">\n  <a href=\"https://forums.sufficientvelocity.com/\" target=\"_blank\" rel=\"noopener noreferrer\">\n    <img src=\"https://forums.sufficientvelocity.com/data/assets/static_light_logo.svg\" alt=\"Sufficient Velocity\" width=\"310\" height=\"108\">\n  </a>\n</p>\n\n<p align=\"center\">\n  <a href=\"https://wanderermaps.com/\" target=\"_blank\" rel=\"noopener noreferrer\">\n    <img src=\"https://cdn.shopify.com/s/files/1/0614/3357/7715/files/Logo_BlackWithBackground_200x.png?v=1644802773\" alt=\"Wanderer Maps logo\">\n  </a>\n</p>\n\n---\n\n## Table of Contents\n\n- [Installation](#installation)\n- [Setup](#setup)\n- [Terminology](#terminology)\n- [Input Types](#input-types)\n- [Configuration Options](#configuration-options)\n- [Callbacks](#callbacks)\n- [Events](#events)\n- [Methods](#methods)\n- [CSS custom properties](#css-custom-properties)\n- [Development](#development)\n- [License](#license)\n\n## Installation\n\nWith [NPM](https://www.npmjs.com/package/choices.js):\n\n```zsh\nnpm install choices.js\n```\n\nWith [Yarn](https://yarnpkg.com/):\n\n```zsh\nyarn add choices.js\n```\n\nFrom a [CDN](https://www.jsdelivr.com/package/npm/choices.js):\n\n**Notes:**\n* There is sometimes a delay before the latest version of Choices is reflected on the CDN.\n* Examples below pin a version (v11.1.0). Check [latest release](https://www.jsdelivr.com/package/npm/choices.js) and update v11.1.0 to the latest tag before using.\n```html\n<!-- Include base CSS (optional) -->\n<link\n  rel=\"stylesheet\"\n  href=\"https://cdn.jsdelivr.net/npm/choices.js/public/assets/styles/base.min.css\"\n/>\n<!-- Or versioned -->\n<link\n  rel=\"stylesheet\"\n  href=\"https://cdn.jsdelivr.net/npm/choices.js@11.1.0/public/assets/styles/base.min.css\"\n/>\n\n<!-- Include Choices CSS -->\n<link\n  rel=\"stylesheet\"\n  href=\"https://cdn.jsdelivr.net/npm/choices.js/public/assets/styles/choices.min.css\"\n/>\n<!-- Or versioned -->\n<link\n  rel=\"stylesheet\"\n  href=\"https://cdn.jsdelivr.net/npm/choices.js@11.1.0/public/assets/styles/choices.min.css\"\n/>\n\n<!-- Include Choices JavaScript (latest) -->\n<script src=\"https://cdn.jsdelivr.net/npm/choices.js/public/assets/scripts/choices.min.js\"></script>\n<!-- Or versioned -->\n<script src=\"https://cdn.jsdelivr.net/npm/choices.js@11.1.0/public/assets/scripts/choices.min.js\"></script>\n```\n\nOr include Choices directly:\n\n```html\n<!-- Include base CSS (optional) -->\n<link rel=\"stylesheet\" href=\"public/assets/styles/base.min.css\" />\n<!-- Include Choices CSS -->\n<link rel=\"stylesheet\" href=\"public/assets/styles/choices.min.css\" />\n<!-- Include Choices JavaScript -->\n<script src=\"/public/assets/scripts/choices.min.js\"></script>\n```\n\n### CSS/SCSS\n\nThe use of `import` of css/scss is supported from webpack.\n\nIn .scss:\n```scss\n@import \"choices.js/src/styles/choices\";\n```\n\nIn .js/.ts:\n```javascript\nimport \"choices.js/public/assets/styles/choices.css\";\n```\n\n## Setup\n\n**Note:** If you pass a selector which targets multiple elements, the first matching element will be used. Versions prior to 8.x.x would return multiple Choices instances.\n\n```js\n  // Pass single element\n  const element = document.querySelector('.js-choice');\n  const choices = new Choices(element);\n\n  // Pass reference\n  const choices = new Choices('[data-trigger]');\n  const choices = new Choices('.js-choice');\n\n  // Pass jQuery element\n  const choices = new Choices($('.js-choice')[0]);\n\n  // Passing options (with default options)\n  const choices = new Choices(element, {\n    silent: false,\n    items: [],\n    choices: [],\n    renderChoiceLimit: -1,\n    maxItemCount: -1,\n    closeDropdownOnSelect: 'auto',\n    singleModeForMultiSelect: false,\n    addChoices: false,\n    addItems: true,\n    addItemFilter: (value) => !!value && value !== '',\n    removeItems: true,\n    removeItemButton: false,\n    removeItemButtonAlignLeft: false,\n    editItems: false,\n    allowHTML: false,\n    allowHtmlUserInput: false,\n    duplicateItemsAllowed: true,\n    delimiter: ',',\n    paste: true,\n    searchEnabled: true,\n    searchChoices: true,\n    searchDisabledChoices: false,\n    searchFloor: 1,\n    searchResultLimit: 4,\n    searchFields: ['label', 'value'],\n    position: 'auto',\n    resetScrollPosition: true,\n    shouldSort: true,\n    shouldSortItems: false,\n    sorter: (a, b) => sortByAlpha,\n    shadowRoot: null,\n    placeholder: true,\n    placeholderValue: null,\n    searchPlaceholderValue: null,\n    prependValue: null,\n    appendValue: null,\n    renderSelectedChoices: 'auto',\n    searchRenderSelectedChoices: true,\n    loadingText: 'Loading...',\n    noResultsText: 'No results found',\n    noChoicesText: 'No choices to choose from',\n    itemSelectText: 'Press to select',\n    uniqueItemText: 'Only unique values can be added',\n    customAddItemText: 'Only values matching specific conditions can be added',\n    addItemText: (value, rawValue) => {\n      return `Press Enter to add <b>\"${value}\"</b>`;\n    },\n    removeItemIconText: () => `Remove item`,\n    removeItemLabelText: (value, rawValue) => `Remove item: ${value}`,\n    maxItemText: (maxItemCount) => {\n      return `Only ${maxItemCount} values can be added`;\n    },\n    valueComparer: (value1, value2) => {\n      return value1 === value2;\n    },\n    classNames: {\n      containerOuter: ['choices'],\n      containerInner: ['choices__inner'],\n      input: ['choices__input'],\n      inputCloned: ['choices__input--cloned'],\n      list: ['choices__list'],\n      listItems: ['choices__list--multiple'],\n      listSingle: ['choices__list--single'],\n      listDropdown: ['choices__list--dropdown'],\n      item: ['choices__item'],\n      itemSelectable: ['choices__item--selectable'],\n      itemDisabled: ['choices__item--disabled'],\n      itemChoice: ['choices__item--choice'],\n      description: ['choices__description'],\n      placeholder: ['choices__placeholder'],\n      group: ['choices__group'],\n      groupHeading: ['choices__heading'],\n      button: ['choices__button'],\n      activeState: ['is-active'],\n      focusState: ['is-focused'],\n      openState: ['is-open'],\n      disabledState: ['is-disabled'],\n      highlightedState: ['is-highlighted'],\n      selectedState: ['is-selected'],\n      flippedState: ['is-flipped'],\n      loadingState: ['is-loading'],\n      invalidState: ['is-invalid'],\n      notice: ['choices__notice'],\n      addChoice: ['choices__item--selectable', 'add-choice'],\n      noResults: ['has-no-results'],\n      noChoices: ['has-no-choices'],\n    },\n    // Choices uses the great Fuse library for searching. You\n    // can find more options here: https://fusejs.io/api/options.html\n    fuseOptions: {\n      includeScore: true\n    },\n    labelId: '',\n    callbackOnInit: null,\n    callbackOnCreateTemplates: null,\n    appendGroupInSearch: false,\n  });\n```\n\n## Terminology\n\n| Word   | Definition                                                                                                                                                                                                                                                                                                              |\n| ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| Choice | A choice is a value a user can select. A choice would be equivalent to the `<option></option>` element within a select input.                                                                                                                                                                                           |\n| Group  | A group is a collection of choices. A group should be seen as equivalent to a `<optgroup></optgroup>` element within a select input.                                                                                                                                                                                    |\n| Item   | An item is an inputted value (text input) or a selected choice (select element). In the context of a select element, an item is equivalent to a selected option element: `<option value=\"Hello\" selected></option>` whereas in the context of a text input an item is equivalent to `<input type=\"text\" value=\"Hello\">` |\n\n## Input Types\n\nChoices works with the following input types, referenced in the documentation as noted.\n\n| HTML Element                                                                                           | Documentation \"Input Type\" |\n| -------------------------------------------------------------------------------------------------------| -------------------------- |\n| [`<input type=\"text\">`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input)               | `text`                     |\n| [`<select>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select)                         | `select-one`               |\n| [`<select multiple>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select#attr-multiple)  | `select-multiple`          |\n\n## Configuration Options\n\n### silent\n\n**Type:** `Boolean` **Default:** `false`\n\n**Input types affected:** `text`, `select-one`, `select-multiple`\n\n**Usage:** Optionally suppress console errors and warnings.\n\n### items\n\n**Type:** `Array` **Default:** `[]`\n\n**Input types affected:** `text`\n\n**Usage:** Add pre-selected items (see terminology) to text input.\n\nPass an array of strings:\n\n`['value 1', 'value 2', 'value 3']`\n\nPass an array of objects:\n\n```\n[{\n  value: 'Value 1',\n  label: 'Label 1',\n  id: 1\n},\n{\n  value: 'Value 2',\n  label: 'Label 2',\n  id: 2,\n  customProperties: {\n    random: 'I am a custom property'\n  }\n}]\n```\n\n### choices\n\n**Type:** `Array` **Default:** `[]`\n\n**Input types affected:** `select-one`, `select-multiple`\n\n**Usage:** Add choices (see terminology) to select input.\n\nPass an array of objects:\n\n```\n[{\n  value: 'Option 1',\n  label: 'Option 1',\n  selected: true,\n  disabled: false,\n},\n{\n  value: 'Option 2',\n  label: 'Option 2',\n  selected: false,\n  disabled: true,\n  customProperties: {\n    description: 'Custom description about Option 2',\n    random: 'Another random custom property'\n  },\n},\n{\n  label: 'Group 1',\n  choices: [{\n    value: 'Option 3',\n    label: 'Option 4',\n    selected: true,\n    disabled: false,\n  },\n  {\n    value: 'Option 2',\n    label: 'Option 2',\n    selected: false,\n    disabled: true,\n    customProperties: {\n      description: 'Custom description about Option 2',\n      random: 'Another random custom property'\n    }\n  }]\n}]\n```\n\n### renderChoiceLimit\n\n**Type:** `Number` **Default:** `-1`\n\n**Input types affected:** `select-one`, `select-multiple`\n\n**Usage:** The amount of choices to be rendered within the dropdown list (\"-1\" indicates no limit). This is useful if you have a lot of choices where it is easier for a user to use the search area to find a choice.\n\n### maxItemCount\n\n**Type:** `Number` **Default:** `-1`\n\n**Input types affected:** `text`, `select-multiple`\n\n**Usage:** The amount of items a user can input/select (\"-1\" indicates no limit).\n\n### closeDropdownOnSelect\n\n**Type:** `Boolean` | 'auto' **Default:** `auto`\n\n**Input types affected:** select-one, select-multiple\n\n**Usage:** Control how the dropdown closes after making a selection for select-one or select-multiple.\n- 'auto' defaults based on backing-element type:\n- select-one: true\n- select-multiple: false\n\n### singleModeForMultiSelect\n\n**Type:** `Boolean` **Default:** `false`\n\n**Input types affected:** select-one, select-multiple\n\n**Usage:** Make select-multiple with a max item count of 1 work similar to select-one does. Selecting an item will auto-close the dropdown and swap any existing item for the just selected choice. If applied to a select-one, it functions as above and not the standard select-one.\n\n### addChoices\n**Type**: `Boolean` **Default:** `false`\n\n**Input types affected:** `select-multiple`, `select-one`\n\n**Usage:** Whether a user can add choices dynamically.\n\n**Note:** `addItems` must also be `true`\n\n### addItems\n\n**Type:** `Boolean` **Default:** `true`\n\n**Input types affected:** `text`\n\n**Usage:** Whether a user can add items.\n\n### removeItems\n\n**Type:** `Boolean` **Default:** `true`\n\n**Input types affected:** `text`, `select-multiple`\n\n**Usage:** Whether a user can remove items.\n\n### removeItemButton\n\n**Type:** `Boolean` **Default:** `false`\n\n**Input types affected:** `text`, `select-one`, `select-multiple`\n\n**Usage:** Whether each item should have a remove button.\n\n### removeItemButtonAlignLeft\n\n**Type:** `Boolean` **Default:** `false`\n\n**Input types affected:** `text`, `select-one`, `select-multiple`\n\n**Usage:** Align item remove button left vs right\n\n### editItems\n\n**Type:** `Boolean` **Default:** `false`\n\n**Input types affected:** `text`\n\n**Usage:** Whether a user can edit items. An item's value can be edited by pressing the backspace.\n\n### allowHTML\n\n**Type:** `Boolean` **Default:** `false`\n\n**Input types affected:** `text`, `select-one`, `select-multiple`\n\n**Usage:** Whether HTML should be rendered in all Choices elements. If `false`, all elements (placeholder, items, etc.) will be treated as plain text. If `true`, this can be used to perform XSS scripting attacks if you load choices from a remote source.\n\n### allowHtmlUserInput\n\n**Type:** `Boolean` **Default:** `false`\n\n**Input types affected:** `text`, `select-one`, `select-multiple`\n\n**Usage:** Whether HTML should be escaped on input when `addItems` or `addChoices` is true. If `false`, user input will be treated as plain text. If `true`, this can be used to perform XSS scripting attacks if you load choices from a remote source.\n\n### duplicateItemsAllowed\n\n**Type:** `Boolean` **Default:** `true`\n\n**Input types affected:** `text`, `select-multiple`, `select-one`\n\n**Usage:** Whether duplicate inputted/chosen items are allowed\n\n### delimiter\n\n**Type:** `String` **Default:** `,`\n\n**Input types affected:** `text`\n\n**Usage:** What divides each value. The default delimiter separates each value with a comma: `\"Value 1, Value 2, Value 3\"`.\n\n### paste\n\n**Type:** `Boolean` **Default:** `true`\n\n**Input types affected:** `text`, `select-multiple`\n\n**Usage:** Whether a user can paste into the input.\n\n### searchEnabled\n\n**Type:** `Boolean` **Default:** `true`\n\n**Input types affected:** `select-one`, `select-multiple`\n\n**Usage:** Whether a search area should be shown.\n\n### searchChoices\n\n**Type:** `Boolean` **Default:** `true`\n\n**Input types affected:** `select-one`\n\n**Usage:** Whether choices should be filtered by input or not. If `false`, the search event will still emit, but choices will not be filtered.\n\n### searchDisabledChoices\n\n**Type:** `Boolean` **Default:** `false`\n\n**Input types affected:** `select-one`, `select-multiple`\n\n**Usage:** Whether disabled choices should be included in search results. If `true`, disabled choices will appear in search results but still cannot be selected. This is useful when you want users to see what options exist but are currently unavailable. Placeholders are always excluded from search results regardless of this setting.\n\n### searchFields\n\n**Type:** `Array/String` **Default:** `['label', 'value']`\n\n**Input types affected:**`select-one`, `select-multiple`\n\n**Usage:** Specify which fields should be used when a user is searching. If you have added custom properties to your choices, you can add these values thus: `['label', 'value', 'customProperties.example']`.\n\n### searchFloor\n\n**Type:** `Number` **Default:** `1`\n\n**Input types affected:** `select-one`, `select-multiple`\n\n**Usage:** The minimum length a search value should be before choices are searched.\n\n### searchResultLimit: 4,\n\n**Type:** `Number` **Default:** `4`\n\n**Input types affected:** `select-one`, `select-multiple`\n\n**Usage:** The maximum amount of search results to show  (\"-1\" indicates no limit).\n\n### shadowRoot\n\n**Type:** Document Element **Default:** null\n\n**Input types affected:** `select-one`, `select-multiple`\n\n**Usage:** You can pass along the shadowRoot from your application like so.\n\n```js\nvar shadowRoot = document\n  .getElementById('wrapper')\n  .attachShadow({ mode: 'open' });\n...\nvar el = shadowRoot.querySelector(...);\nvar choices = new Choices(el, {\n  shadowRoot: shadowRoot,\n});\n```\n\n### position\n\n**Type:** `String` **Default:** `auto`\n\n**Input types affected:** `select-one`, `select-multiple`\n\n**Usage:** Whether the dropdown should appear above (`top`) or below (`bottom`) the input. By default, if there is not enough space within the window the dropdown will appear above the input, otherwise below it.\n\n### resetScrollPosition\n\n**Type:** `Boolean` **Default:** `true`\n\n**Input types affected:** `select-multiple`\n\n**Usage:** Whether the scroll position should reset after adding an item.\n\n### addItemFilter\n\n**Type:** `string | RegExp | Function` **Default:** `null`\n\n**Input types affected:** `text`\n\n**Usage:** A RegExp or string (will be passed to RegExp constructor internally) or filter function that will need to return `true` for a user to successfully add an item.\n\n**Example:**\n\n```js\n// Only adds items matching the text test\nnew Choices(element, {\n  addItemFilter: (value) => {\n    return ['orange', 'apple', 'banana'].includes(value);\n  };\n});\n\n// only items ending to `-red`\nnew Choices(element, {\n  addItemFilter: '-red$';\n});\n\n```\n\n### shouldSort\n\n**Type:** `Boolean` **Default:** `true`\n\n**Input types affected:** `select-one`, `select-multiple`\n\n**Usage:** Whether choices and groups should be sorted. If false, choices/groups will appear in the order they were given.\n\n### shouldSortItems\n\n**Type:** `Boolean` **Default:** `false`\n\n**Input types affected:** `text`, `select-multiple`\n\n**Usage:** Whether items should be sorted. If false, items will appear in the order they were selected.\n\n### sorter\n\n**Type:** `Function` **Default:** sortByAlpha\n\n**Input types affected:** `select-one`, `select-multiple`\n\n**Usage:** The function that will sort choices and items before they are displayed (unless a user is searching). By default choices and items are sorted by alphabetical order.\n\n**Example:**\n\n```js\n// Sorting via length of label from largest to smallest\nconst example = new Choices(element, {\n  sorter: function(a, b) {\n    return b.label.length - a.label.length;\n  },\n});\n```\n\n### placeholder\n\n**Type:** `Boolean` **Default:** `true`\n\n**Input types affected:** `text`\n\n**Usage:** Whether the input should show a placeholder. Used in conjunction with `placeholderValue`. If `placeholder` is set to true and no value is passed to `placeholderValue`, the passed input's placeholder attribute will be used as the placeholder value.\n\n**Note:** For select boxes, the recommended way of adding a placeholder is as follows:\n\n```html\n<select data-placeholder=\"This is a placeholder\">\n  <option>...</option>\n  <option>...</option>\n  <option>...</option>\n</select>\n```\n\nFor backward compatibility, `<option value=\"\">This is a placeholder</option>` and `<option placeholder>This is a placeholder</option>` are also supported.\n\n### placeholderValue\n\n**Type:** `String` **Default:** `null`\n\n**Input types affected:** `text`\n\n**Usage:** The value of the inputs placeholder.\n\n### searchPlaceholderValue\n\n**Type:** `String` **Default:** `null`\n\n**Input types affected:** `select-one`\n\n**Usage:** The value of the search inputs placeholder.\n\n### prependValue\n\n**Type:** `String` **Default:** `null`\n\n**Input types affected:** `text`, `select-one`, `select-multiple`\n\n**Usage:** Prepend a value to each item added/selected.\n\n### appendValue\n\n**Type:** `String` **Default:** `null`\n\n**Input types affected:** `text`, `select-one`, `select-multiple`\n\n**Usage:** Append a value to each item added/selected.\n\n### renderSelectedChoices\n\n**Type:** `String` **Default:** `auto`\n\n**Input types affected:** `select-multiple`\n\n**Usage:** Whether selected choices should be removed from the list. By default choices are removed when they are selected in multiple select box. To always render choices pass `always`.\n\n### searchRenderSelectedChoices\n\n**Type:** `Boolean` **Default:** `true'`\n\n**Input types affected:** `select-multiple`\n\n**Usage:** Whether selected choices should be removed from the list during search.\n\n**Example:**\n\n```js\n// Hide selected choices from search results\nconst example = new Choices(element, {\n  searchRenderSelectedChoices: false,\n});\n```\n\n### loadingText\n\n**Type:** `String` **Default:** `Loading...`\n\n**Input types affected:** `select-one`, `select-multiple`\n\n**Usage:** The text that is shown whilst choices are being populated via AJAX.\n\n### noResultsText\n\n**Type:** `String/Function` **Default:** `No results found`\n\n**Input types affected:** `select-one`, `select-multiple`\n\n**Usage:** The text that is shown when a user's search has returned no results. Optionally pass a function returning a string.\n\n### noChoicesText\n\n**Type:** `String/Function` **Default:** `No choices to choose from`\n\n**Input types affected:** `select-multiple`, `select-one`\n\n**Usage:** The text that is shown when a user has selected all possible choices, or no choices exist. Optionally pass a function returning a string.\n\n### itemSelectText\n\n**Type:** `String` **Default:** `Press to select`\n\n**Input types affected:** `select-multiple`, `select-one`\n\n**Usage:** The text that is shown when a user hovers over a selectable choice. Set to empty to not reserve space for this text.\n\n### addItemText\n\n**Type:** `String/Function` **Default:** `Press Enter to add \"${value}\"` **Arguments:** `value`, `valueRaw`\n\n**Input types affected:** `text`, `select-one`, `select-multiple`\n\n**Usage:** The text that is shown when a user has inputted a new item but has not pressed the enter key. To access the current input value, pass a function with a `value` argument (see the [default config](https://github.com/Choices-js/Choices#setup) for an example), otherwise pass a string.\n\nReturn type must be safe to insert into HTML (ie use the 1st argument which is sanitised)\n\n### removeItemIconText\n\n**Type:** `String/Function` **Default:** `Remove item\"` **Arguments:** `value`, `valueRaw`, `item`\n\n**Input types affected:** `text`, `select-one`, `select-multiple`\n\n**Usage:** The text/icon for the remove button. To access the item's value, pass a function with a `value` argument (see the **default config** [https://github.com/Choices-js/Choices#setup] for an example), otherwise pass a string.\nTo access the item's label, use the 3rd argument. *Note*; this label is not escaped.\n\nReturn type must be safe to insert into HTML (ie use the 1st argument which is sanitised)\n\n### removeItemLabelText\n\n**Type:** `String/Function` **Default:** `Remove item: ${value}\"` **Arguments:** `value`, `valueRaw`, `item`\n\n**Input types affected:** `text`, `select-one`, `select-multiple`\n\n**Usage:** The text for the remove button's aria label. To access the item's value, pass a function with a `value` argument (see the **default config** [https://github.com/Choices-js/Choices#setup] for an example), otherwise pass a string.\nTo access the item's label, use the 3rd argument. *Note*; this label is not escaped.\n\nReturn type must be safe to insert into HTML (ie use the 1st argument which is sanitised)\n\n### maxItemText\n\n**Type:** `String/Function` **Default:** `Only ${maxItemCount} values can be added` **Arguments:** `maxItemCount`\n\n**Input types affected:** `text`\n\n**Usage:** The text that is shown when a user has focus on the input but has already reached the [max item count](https://github.com/Choices-js/Choices#maxitemcount). To access the max item count, pass a function with a `maxItemCount` argument (see the [default config](https://github.com/Choices-js/Choices#setup) for an example), otherwise pass a string.\n\n### valueComparer\n\n**Type:** `Function` **Default:** `strict equality` **Arguments:** `value1`, `value2`\n\n**Input types affected:** `select-one`, `select-multiple`\n\n**Usage:** A custom compare function used when finding choices by value (using `setChoiceByValue`).\n\n**Example:**\n\n```js\nconst example = new Choices(element, {\n  valueComparer: (a, b) => value.trim() === b.trim(),\n});\n```\n\n### labelId\n\n**Type:** `String` **Default:** ``\n\n**Input types affected:** `select-one`, `select-multiple`\n\n**Usage:** The labelId improves accessibility. If set, it will add aria-labelledby to the choices element.\n\n### classNames\n\n**Type:** `Object` **Default:**\n\n```\nclassNames: {\n  containerOuter: ['choices'],\n  containerInner: ['choices__inner'],\n  input: ['choices__input'],\n  inputCloned: ['choices__input--cloned'],\n  list: ['choices__list'],\n  listItems: ['choices__list--multiple'],\n  listSingle: ['choices__list--single'],\n  listDropdown: ['choices__list--dropdown'],\n  item: ['choices__item'],\n  itemSelectable: ['choices__item--selectable'],\n  itemDisabled: ['choices__item--disabled'],\n  itemChoice: ['choices__item--choice'],\n  description: ['choices__description'],\n  placeholder: ['choices__placeholder'],\n  group: ['choices__group'],\n  groupHeading: ['choices__heading'],\n  button: ['choices__button'],\n  activeState: ['is-active'],\n  focusState: ['is-focused'],\n  openState: ['is-open'],\n  disabledState: ['is-disabled'],\n  highlightedState: ['is-highlighted'],\n  selectedState: ['is-selected'],\n  flippedState: ['is-flipped'],\n  loadingState: ['is-loading'],\n  invalidState: ['is-invalid'],\n  notice: ['choices__notice'],\n  addChoice: ['choices__item--selectable', 'add-choice'],\n  noResults: ['has-no-results'],\n  noChoices: ['has-no-choices'],\n}\n```\n\n**Input types affected:** `text`, `select-one`, `select-multiple`\n\n**Usage:** Classes added to HTML generated by Choices. By default classnames follow the [BEM](http://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax/) notation.\n\n## Callbacks\n\n**Note:** For each callback, `this` refers to the current instance of Choices. This can be useful if you need access to methods (`this.disable()`) or the config object (`this.config`).\n\n### callbackOnInit\n\n**Type:** `Function` **Default:** `null`\n\n**Input types affected:** `text`, `select-one`, `select-multiple`\n\n**Usage:** Function to run once Choices initialises.\n\n### callbackOnCreateTemplates(strToEl: (str: string) => HTMLElement, escapeForTemplate: (allowHTML: boolean, s: StringUntrusted | StringPreEscaped | string) => string, getClassNames: (s: Array<string> | string) => string)\n\n**Type:** `Function` **Default:** `null` **Arguments:** `strToEl`, `escapeForTemplate`, `getClassNames`\n\n**Input types affected:** `text`, `select-one`, `select-multiple`\n\n**Usage:** Function to run on template creation. Through this callback it is possible to provide custom templates for the various components of Choices (see terminology). For Choices to work with custom templates, it is important you maintain the various data attributes defined [here](https://github.com/Choices-js/Choices/blob/main/src/scripts/templates.ts).\nIf you want just extend a little original template then you may use `Choices.defaults.templates` to get access to\noriginal template function.\n\nTemplates receive the full Choices config as the first argument to any template, which allows you to conditionally display things based on the options specified.\n\n@note For each callback, `this` refers to the current instance of Choices. This can be useful if you need access to methods `(this.disable())`.\n\n**Example:**\n\n```js\nconst example = new Choices(element, {\n  callbackOnCreateTemplates: (strToEl, escapeForTemplate, getClassNames) => ({\n    input: (...args) =>\n      Object.assign(Choices.defaults.templates.input.call(this, ...args), {\n        type: 'email',\n      }),\n  }),\n});\n```\n\nor more complex:\n\n```js\n// StrToEl = (str: string) => HTMLElement | HTMLInputElement | HTMLOptionElement;\n// EscapeForTemplateFn = (allowHTML: boolean, s: StringUntrusted | StringPreEscaped | string) => string;\n// GetClassNamesFn = (s: string | Array<string>) => string;\nconst example = new Choices(element, {\n  callbackOnCreateTemplates: function(strToEl /*:StrToEl*/, escapeForTemplate /*:EscapeForTemplateFn*/, getClassNames /*:GetClassNamesFn*/) {\n    return {\n      item: ({ classNames }, data) => {\n        return strToEl(`\n          <div class=\"${getClassNames(classNames.item).join(' ')} ${\n          getClassNames(data.highlighted\n            ? classNames.highlightedState\n            : classNames.itemSelectable).join(' ')\n        } ${\n          data.placeholder ? classNames.placeholder : ''\n        }\" data-item data-id=\"${data.id}\" data-value=\"${escapeForTemplate(true, data.value)}\" ${\n          data.active ? 'aria-selected=\"true\"' : ''\n        } ${data.disabled ? 'aria-disabled=\"true\"' : ''}>\n            <span>&bigstar;</span> ${escapeForTemplate(true, data.label)}\n          </div>\n        `);\n      },\n      choice: ({ classNames }, data) => {\n        return strToEl(`\n          <div class=\"${getClassNames(classNames.item).join(' ')} ${getClassNames(classNames.itemChoice).join(' ')} ${\n          getClassNames(data.disabled ? classNames.itemDisabled : classNames.itemSelectable).join(' ')\n        }\" data-select-text=\"${this.config.itemSelectText}\" data-choice ${\n          data.disabled\n            ? 'data-choice-disabled aria-disabled=\"true\"'\n            : 'data-choice-selectable'\n        } data-id=\"${data.id}\" data-value=\"${escapeForTemplate(true, data.value)}\" ${\n          data.groupId > 0 ? 'role=\"treeitem\"' : 'role=\"option\"'\n        }>\n            <span>&bigstar;</span> ${escapeForTemplate(true, data.label)}\n          </div>\n        `);\n      },\n    };\n  },\n});\n```\n\n## Events\n\n**Note:** Events fired by Choices behave the same as standard events. Each event is triggered on the element passed to Choices (accessible via `this.passedElement`. Arguments are accessible within the `event.detail` object.\n\n**Example:**\n\n```js\nconst element = document.getElementById('example');\nconst example = new Choices(element);\n\nelement.addEventListener(\n  'addItem',\n  function(event) {\n    // do something creative here...\n    console.log(event.detail.id);\n    console.log(event.detail.value);\n    console.log(event.detail.label);\n    console.log(event.detail.customProperties);\n    console.log(event.detail.groupValue);\n  },\n  false,\n);\n\n// or\nconst example = new Choices(document.getElementById('example'));\n\nexample.passedElement.element.addEventListener(\n  'addItem',\n  function(event) {\n    // do something creative here...\n    console.log(event.detail.id);\n    console.log(event.detail.value);\n    console.log(event.detail.label);\n    console.log(event.detail.customProperties);\n    console.log(event.detail.groupValue);\n  },\n  false,\n);\n```\n\n### addItem\n\n**Payload:** `id, highlighted, labelClass, labelDescription, customProperties, disabled, active, label, placeholder, value, groupValue, element, keyCode`\n\n**Input types affected:** `text`, `select-one`, `select-multiple`\n\n**Usage:** Triggered each time an item is added (programmatically or by the user).\n\n### removeItem\n\n**Payload:** `id, highlighted, labelClass, labelDescription, customProperties, disabled, active, label, placeholder, value, groupValue, element, keyCode`\n\n**Input types affected:** `text`, `select-one`, `select-multiple`\n\n**Usage:** Triggered each time an item is removed (programmatically or by the user).\n\n### highlightItem\n\n**Payload:** `id, highlighted, labelClass, labelDescription, customProperties, disabled, active, label, placeholder, value, groupValue, element, keyCode`\n\n**Input types affected:** `text`, `select-multiple`\n\n**Usage:** Triggered each time an item is highlighted.\n\n### unhighlightItem\n\n**Payload:** `id, highlighted, labelClass, labelDescription, customProperties, disabled, active, label, placeholder, value, groupValue, element, keyCode`\n\n**Input types affected:** `text`, `select-multiple`\n\n**Usage:** Triggered each time an item is unhighlighted.\n\n### choice\n\n**Payload:** `id, highlighted, labelClass, labelDescription, customProperties, disabled, active, label, placeholder, value, groupValue, element, keyCode`\n\n**Input types affected:** `select-one`, `select-multiple`\n\n**Usage:** Triggered each time a choice is selected **by a user**, regardless if it changes the value of the input.\n`choice` is a Choice object here (see terminology or typings file)\n\n### change\n\n**Payload:** `value: string`\n\n**Input types affected:** `text`, `select-one`, `select-multiple`\n\n**Usage:** Triggered each time an item is added/removed **by a user**.\n\n### search\n\n**Payload:** `value: string`, `resultCount: number`\n\n**Input types affected:** `select-one`, `select-multiple`\n\n**Usage:** Triggered when a user types into an input to search choices. When a search is ended, a search event with an empty value with no resultCount is triggered.\n\n### showDropdown\n\n**Payload:** -\n\n**Input types affected:** `select-one`, `select-multiple`\n\n**Usage:** Triggered when the dropdown is shown.\n\n### hideDropdown\n\n**Payload:** -\n\n**Input types affected:** `select-one`, `select-multiple`\n\n**Usage:** Triggered when the dropdown is hidden.\n\n### highlightChoice\n\n**Payload:** `el`\n\n**Input types affected:** `select-one`, `select-multiple`\n\n**Usage:** Triggered when a choice from the dropdown is highlighted.\nThe `el` argument is choices.passedElement object that was affected.\n\n## Methods\n\nMethods can be called either directly or by chaining:\n\n```js\n// Calling a method by chaining\nconst choices = new Choices(element, {\n  addItems: false,\n  removeItems: false,\n})\n  .setValue(['Set value 1', 'Set value 2'])\n  .disable();\n\n// Calling a method directly\nconst choices = new Choices(element, {\n  addItems: false,\n  removeItems: false,\n});\n\nchoices.setValue(['Set value 1', 'Set value 2']);\nchoices.disable();\n```\n\n### destroy();\n\n**Input types affected:** `text`, `select-multiple`, `select-one`\n\n**Usage:** Kills the instance of Choices, removes all event listeners and returns passed input to its initial state.\n\n### init();\n\n**Input types affected:** `text`, `select-multiple`, `select-one`\n\n**Usage:** Creates a new instance of Choices, adds event listeners, creates templates and renders a Choices element to the DOM.\n\n**Note:** This is called implicitly when a new instance of Choices is created. This would be used after a Choices instance had already been destroyed (using `destroy()`).\n\n### refresh(withEvents: boolean = false, selectFirstOption: boolean = false);\n\n**Input types affected:** `select-multiple`, `select-one`\n\n**Usage:** Reads options from backing `<select>` element, and recreates choices. Existing items are preserved. When `withEvents` is truthy, only `addItem` events are generated.\n\n### highlightAll();\n\n**Input types affected:** `text`, `select-multiple`\n\n**Usage:** Highlight each chosen item (selected items can be removed).\n\n### unhighlightAll();\n\n**Input types affected:** `text`, `select-multiple`\n\n**Usage:** Un-highlight each chosen item.\n\n### removeActiveItemsByValue(value: string);\n\n**Input types affected:** `text`, `select-multiple`\n\n**Usage:** Remove each item by a given value.\n\n### removeActiveItems(excludedId?: number);\n\n**Input types affected:** `text`, `select-multiple`\n\n**Usage:** Remove each selectable item.\n\n## removeChoice(value: string);\n\n**Input types affected:** `text`, `select-multiple`, `select-one`\n\n**Usage:** Remove an option/item by value\n\n### removeHighlightedItems(runEvent?: boolean);\n\n**Input types affected:** `text`, `select-multiple`\n\n**Usage:** Remove each item the user has selected.\n\n### showDropdown(preventInputFocus?: boolean);\n\n**Input types affected:** `select-one`, `select-multiple`\n\n**Usage:** Show choices list dropdown.\n\n### hideDropdown(preventInputFocus?: boolean);\n\n**Input types affected:** ``select-one`, `select-multiple`\n\n**Usage:** Hide choices list dropdown.\n\n### setChoices(choicesArrayOrFetcher?: (InputChoice | InputGroup)[] | ((instance: Choices) => (InputChoice | InputGroup)[] | Promise<(InputChoice | InputGroup)[]>), value?: string | null, label?: string, replaceChoices?: boolean = false, clearSearchFlag?: boolean = false, replaceItems?: boolean = false): this | Promise<this>;\n\n**Input types affected:** `select-one`, `select-multiple`\n\n**Usage:** Set choices of select input via an array of objects (or function that returns array of object or promise of it), a value field name and a label field name.\n\nThis behaves the similar as passing items via the `choices` option but can be called after initialising Choices. This can also be used to add groups of choices (see example 3); Optionally pass a true `replaceChoices` value to remove any existing choices. Optionally pass a true `replaceItems` value to remove any items, if false choices for selected items are preserved. Optionally pass a `customProperties` object to add additional data to your choices (useful when searching/filtering etc). Passing an empty array as the first parameter, and a true `replaceChoices` is the same as calling `clearChoices` (see below).\n\n**Example 1:**\n\n```js\nconst example = new Choices(element);\n\nexample.setChoices(\n  [\n    { value: 'One', label: 'Label One', disabled: true },\n    { value: 'Two', label: 'Label Two', selected: true },\n    { value: 'Three', label: 'Label Three' },\n  ],\n  'value',\n  'label',\n  false,\n);\n```\n\n**Example 2:**\n\n```js\nconst example = new Choices(element);\n\n// Passing a function that returns Promise of choices\nexample.setChoices(async () => {\n  try {\n    const items = await fetch('/items');\n    return items.json();\n  } catch (err) {\n    console.error(err);\n  }\n});\n```\n\n**Example 3:**\n\n```js\nconst example = new Choices(element);\n\nexample.setChoices(\n  [\n    {\n      label: 'Group one',\n      disabled: false,\n      choices: [\n        { value: 'Child One', label: 'Child One', selected: true },\n        { value: 'Child Two', label: 'Child Two', disabled: true },\n        { value: 'Child Three', label: 'Child Three' },\n      ],\n    },\n    {\n      label: 'Group two',\n      disabled: false,\n      choices: [\n        { value: 'Child Four', label: 'Child Four', disabled: true },\n        { value: 'Child Five', label: 'Child Five' },\n        {\n          value: 'Child Six',\n          label: 'Child Six',\n          customProperties: {\n            description: 'Custom description about child six',\n            random: 'Another random custom property',\n          },\n        },\n      ],\n    },\n  ],\n  'value',\n  'label',\n  false,\n);\n```\n\n### clearChoices(clearOptions: boolean = true, clearItems: boolean = false);\n\n**Input types affected:** `select-one`, `select-multiple`\n\n**Usage:** Clear all choices from select including any selected items. Does **not** reset the search state.\n- `clearOptions` If true, clears the backing options from the `<select>` element\n- `clearItems` If false, preserves selected items instead of clearing them\n\n### getValue(valueOnly?: boolean): string[] | EventChoice[] | EventChoice | string;\n\n**Input types affected:** `text`, `select-one`, `select-multiple`\n\n**Usage:** Get value(s) of input (i.e. inputted items (text) or selected choices (select)). Optionally pass an argument of `true` to only return values rather than value objects.\n\n**Example:**\n\n```js\nconst example = new Choices(element);\nconst values = example.getValue(true); // returns ['value 1', 'value 2'];\nconst valueArray = example.getValue(); // returns [{ active: true, choiceId: 1, highlighted: false, id: 1, label: 'Label 1', value: 'Value 1'},  { active: true, choiceId: 2, highlighted: false, id: 2, label: 'Label 2', value: 'Value 2'}];\n```\n\n### setValue(items: string[] | InputChoice[]): this;\n\n**Input types affected:** `text`, `select-one`, `select-multiple`\n\n**Usage:** Set value of input based on an array of objects or strings. This behaves exactly the same as passing items via the `items` option but can be called after initialising Choices.\n\n**Example:**\n\n```js\nconst example = new Choices(element);\n\n// via an array of objects\nexample.setValue([\n  { value: 'One', label: 'Label One' },\n  { value: 'Two', label: 'Label Two' },\n  { value: 'Three', label: 'Label Three' },\n]);\n\n// or via an array of strings\nexample.setValue(['Four', 'Five', 'Six']);\n```\n\n### setChoiceByValue(value: string | string[]);\n\n**Input types affected:** `select-one`, `select-multiple`\n\n**Usage:** Set value of input based on existing Choice. `value` can be either a single string or an array of strings\n\n**Example:**\n\n```js\nconst example = new Choices(element, {\n  choices: [\n    { value: 'One', label: 'Label One' },\n    { value: 'Two', label: 'Label Two', disabled: true },\n    { value: 'Three', label: 'Label Three' },\n  ],\n});\n\nexample.setChoiceByValue('Two'); // Choice with value of 'Two' has now been selected.\n```\n\n### clearStore();\n\n**Input types affected:** `text`, `select-one`, `select-multiple`\n\n**Usage:** Removes all items, choices and groups. Resets the search state. Use with caution.\n\n### clearInput();\n\n**Input types affected:** `text`\n\n**Usage:** Clear input of any user inputted text.\n\n### disable();\n\n**Input types affected:** `text`, `select-one`, `select-multiple`\n\n**Usage:** Disables input from accepting new value/selecting further choices.\n\n### enable();\n\n**Input types affected:** `text`, `select-one`, `select-multiple`\n\n**Usage:** Enables input to accept new values/select further choices.\n\n## Browser compatibility\n\nChoices is compiled using [Babel](https://babeljs.io/) targeting browsers [with more than 1% of global usage](https://github.com/Choices-js/Choices/blob/main/.browserslistrc) and expecting that features [listed below](https://github.com/Choices-js/Choices/blob/main/.eslintrc.json#L62) are available or polyfilled in browser.\nYou may see exact list of target browsers by running `npm exec browserslist` within this repository folder.\nIf you need to support a browser that does not have one of the features listed below,\nI suggest including a polyfill from [cdnjs.cloudflare.com/polyfill](https://cdnjs.cloudflare.com/polyfill):\n\n**Polyfill example used for the demo:**\n\n```html\n<script src=\"https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?version=4.8.0&features=Array.from%2CArray.prototype.find%2CArray.prototype.includes%2CSymbol%2CSymbol.iterator%2CDOMTokenList%2CObject.assign%2CCustomEvent%2CElement.prototype.classList%2CElement.prototype.closest%2CElement.prototype.dataset%2CElement.prototype.replaceChildren\"></script>\n```\n\n**Features used in Choices:**\n\n```polyfills\nArray.from\nArray.prototype.find\nArray.prototype.includes\nSymbol\nSymbol.iterator\nDOMTokenList\nObject.assign\nCustomEvent\nElement.prototype.classList\nElement.prototype.closest\nElement.prototype.dataset\nElement.prototype.replaceChildren\n```\n\n## CSS custom properties\n\nSince version `11.2`, you are able to customize the behavior and CSS of Choices.js using the following\n[custom properties](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_cascading_variables/Using_CSS_custom_properties).\n\n| Property                          | Default                                   | Description                                                                 |\n|-----------------------------------|-------------------------------------------|-----------------------------------------------------------------------------|\n| `--choices-darken`                | `black`                                   | Darken color used within the color-mix                                      |\n| `--choices-lighten`               | `white`                                   | Ligten color used within the color-mix                                      |\n| `--choices-bg-color`              | `#f9f9f9`                                 | Background color of the choices element                                     |\n| `--choices-bg-color-disabled`     | `#eaeaea`                                 | Background color of a disabled choices element                              |\n| `--choices-bg-color-dropdown`     | `#fff`                                    | Background color of the dropdown                                            |\n| `--choices-text-color`            | `#333`                                    | Text color of choices                                                       |\n| `--choices-keyline-color`         | `#ddd`                                    | Border-colors within choices                                                |\n| `--choices-primary-color`         | `#005F75`                                 | Primary color                                                               |\n| `--choices-disabled-color`        | `#eaeaea`                                 | Background color of disabled items                                          |\n| `--choices-item-disabled-color`   | `#fff`                                    | Text color of disabled items                                                |\n| `--choices-invalid-color`         | `#d33141`                                 | Border color of the invalid state                                           |\n| `--choices-highlighted-color`     | `#f2f2f2`                                 | Highlight background of the choices items                                   |\n| `--choices-highlight-color`       | `#005F75`                                 | Focus color of the choices button                                           |\n| `--choices-font-size-lg`          | `16px`                                    | Basic font size for choices                                                 |\n| `--choices-font-size-md`          | `14px`                                    | Font size for medium choices items, e.g. the input field                    |\n| `--choices-font-size-sm`          | `12px`                                    | Font size for the small choices items, e.g. select multiple or explanations |\n| `--choices-guttering`             | `24px`                                    | Margin-Bottom of the choices wrapper                                        |\n| `--choices-border-radius`         | `2.5px`                                   | Border-radius of the choices element                                        |\n| `--choices-border-radius-item`    | `20px`                                    | Border-radius of the choices items                                          |\n| `--choices-z-index`               | `1`                                       | z-index of the active choices dropdown                                      |\n| `--choices-input-height`          | `44px`                                    | Height of the choices inner element                                         |\n| `--choices-width`                 | `100%`                                    | Width of the choices inner element                                          |\n| `--choices-base-border`           | `1px solid var( --choices-keyline-color)` | Bottom-border of the choices inner element                                  |\n| `--choices-multiple-item-margin`  | `3.75px`                                  | Margin of the dropdown items (multiple mode)                                |\n| `--choices-multiple-item-padding` | `4px 10px`                                | Padding of the dropdown items (multiple mode)                               |\n| `--choices-dropdown-item-padding` | `10px`                                    | Padding of the choices dropdown items                                       |\n| `--choices-list-single-padding`   | `4px 16px 4px 4px`                        | Padding of the listbox description                                          |\n| `--choices-input-margin-bottom`   | `5px`                                     | Margin-bottom of the choices input (text inputs)                            |\n| `--choices-input-padding`         | `4px 0 4px 2px`                           | Padding of the choices input                                                |\n| `--choices-inner-padding`         | `7.5px 7.5px 3.75px`                      | Padding of the choices inner element                                        |\n| `--choices-inner-one-padding`     | `7.5px`                                   | Padding of the choices inner element (Single select input)                  |\n| `--choices-arrow-size`            | `5px`                                     | Size of the choices dropdown symbol                                         |\n| `--choices-arrow-margin-top`      | `-2.5px`                                  | Top offset of the dropdown symbol                                           |\n| `--choices-arrow-margin-top-open` | `-7.5px`                                  | Top offset of the active dropdown symbol                                    |\n| `--choices-arrow-right`           | `11.5px`                                  | Right offset of the dropdown symbol                                         |\n| `--choices-icon-cross`            | `url(\"...\")`                              | Button image                                                                |\n| `--choices-icon-cross-inverse`    | `url(\"...\")`                              | Button image (inversed color)                                               |\n| `--choices-button-offset`         | `8px`                                     | Button offset                                                               |\n| `--choices-button-dimension`      | `8px`                                     | Button background size                                                      |\n| `--choices-button-line-height`    | `1`                                       | Button line height                                                          |\n| `--choices-button-border-radius`  | `0`                                       | Button border-radius                                                        |\n| `--choices-button-opacity`        | `0.75`                                    | Button opacity                                                              |\n| `--choices-button-opacity-hover`  | `1`                                       | Button opacity on hover                                                     |\n| `--choices-placeholder-opacity`   | `0.5`                                     | Placeholder opacity                                                         |\n\n### Dark mode example\n\nThe current demo page uses the following variables for its dark mode\n\n```css\n@media (prefers-color-scheme: dark) {\n  :root {\n    --choices-primary-color: #38daff;\n    --choices-item-color: black;\n    --choices-bg-color: #101010;\n    --choices-bg-color-dropdown: #101010;\n    --choices-keyline-color: #3b3e40;\n    --choices-bg-color-disabled: #181a1b;\n    --choices-item-disabled-color: #eee;\n    --choices-disabled-color: #2d2d2d;\n    --choices-highlighted-color: #16292d;\n    --choices-icon-cross: url(\"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjEiIHZpZXdCb3g9IjAgMCAyMSAyMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSIjMDAwIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0yLjU5Mi4wNDRsMTguMzY0IDE4LjM2NC0yLjU0OCAyLjU0OEwuMDQ0IDIuNTkyeiIvPjxwYXRoIGQ9Ik0wIDE4LjM2NEwxOC4zNjQgMGwyLjU0OCAyLjU0OEwyLjU0OCAyMC45MTJ6Ii8+PC9nPjwvc3ZnPg==\");\n    --choices-icon-cross-inverse: url(\"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjEiIHZpZXdCb3g9IjAgMCAyMSAyMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSIjRkZGIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0yLjU5Mi4wNDRsMTguMzY0IDE4LjM2NC0yLjU0OCAyLjU0OEwuMDQ0IDIuNTkyeiIvPjxwYXRoIGQ9Ik0wIDE4LjM2NEwxOC4zNjQgMGwyLjU0OCAyLjU0OEwyLjU0OCAyMC45MTJ6Ii8+PC9nPjwvc3ZnPg==\");\n  }\n}\n```\n\n## Development\n\nTo setup a local environment: clone this repo, navigate into its directory in a terminal window and run the following command:\n\n`npm install`\n\n### playwright\n\ne2e (End-to-end) tests are implemented using playwright, which requires installing likely with OS support.\n\n`npx playwright install`\n`npx playwright install-deps `\n\nFor JetBrain IDE's the `Test automation` plugin is recommended:\nhttps://plugins.jetbrains.com/plugin/20175-test-automation\nFor usage see:\nhttps://www.jetbrains.com/help/phpstorm/playwright.html\n\n### NPM tasks\n\n| Task                      | Usage                                                        |\n|---------------------------|--------------------------------------------------------------|\n| `npm run start`           | Fire up local server for development                         |\n| `npm run test:unit`       | Run sequence of tests once                                   |\n| `npm run test:unit:watch` | Fire up test server and re-test on file change               |\n| `npm run test:e2e`        | Run sequence of e2e tests (with local server)                |\n| `npm run test`            | Run both unit and e2e tests                                  |\n| `npm run playwright:gui`  | Run Playwright e2e tests (GUI)                               |\n| `npm run playwright:cli`  | Run Playwright e2e tests (CLI)                               |\n| `npm run js:build`        | Compile Choices to an uglified JavaScript file               |\n| `npm run css:watch`       | Watch SCSS files for changes. On a change, run build process |\n| `npm run css:build`       | Compile, minify and prefix SCSS files to CSS                 |\n\n\n### Build flags\n\nChoices supports various environment variables as build-flags to enable/disable features.\nThe pre-built bundles these features set, and tree shaking uses the non-used parts.\n\n#### CHOICES_SEARCH_FUSE\n**Values:** `full` / `basic` / `null`\n**Default:** `full`\n\nFuse.js support a `full`/`basic` profile. `full` adds additional logic operations, which aren't used by default with Choices. The `null` option drops Fuse.js as a dependency and instead uses a simple prefix only search feature.\n\n#### CHOICES_SEARCH_KMP\n**Values:** `1` / `0`\n**Default:** `0`\n\nIf `CHOICES_SEARCH_FUSE` is `null`, this enables an `indexOf`-like [Knuth–Morris–Pratt algorithm](https://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm). Useful for very large data sets, without fuzzy searching.\n\n#### CHOICES_CAN_USE_DOM\n**Values:** `1` / `0`\n**Default:** `1`\n\nAllows loading Choices into a non-browser environment.\n\n### Interested in contributing?\n\nWe're always interested in having more active maintainers.  Please get in touch if you're interested 👍\n\n## License\n\nMIT License\n\n## Web component\n\nWant to use Choices as a web component? You're in luck. Adidas have built one for their design system which can be found [here](https://github.com/adidas/choicesjs-stencil).\n\n## Misc\n\nThanks to [@mikefrancis](https://github.com/mikefrancis/) for [sending me on a hunt](https://twitter.com/_mikefrancis/status/701797835826667520) for a non-jQuery solution for select boxes that eventually led to this being built!\n"
  },
  {
    "path": "babel.config.json",
    "content": "{\n  \"presets\": [\"@babel/preset-env\", \"@babel/preset-typescript\"],\n  \"plugins\": [\n    \"@babel/plugin-transform-object-rest-spread\"\n  ]\n}\n"
  },
  {
    "path": "jsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"checkJs\": true,\n    \"target\": \"es2020\",\n    \"lib\": [\"esnext\", \"dom\"],\n    \"types\": [],\n    \"strict\": true,\n    \"moduleResolution\": \"node\",\n    /* Additional Checks */\n    \"noImplicitAny\": false,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"noImplicitReturns\": true,\n    \"noFallthroughCasesInSwitch\": true,\n    \"strictNullChecks\": false\n  }\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"choices.js\",\n  \"version\": \"11.2.1\",\n  \"description\": \"A vanilla JS customisable text input/select box plugin\",\n  \"main\": \"./public/assets/scripts/choices.js\",\n  \"module\": \"./public/assets/scripts/choices.mjs\",\n  \"unpkg\": \"./public/assets/scripts/choices.js\",\n  \"jsdelivr\": \"./public/assets/scripts/choices.js\",\n  \"types\": \"./public/types/src/index.d.ts\",\n  \"exports\": {\n    \".\": {\n      \"types\": \"./public/types/src/index.d.ts\",\n      \"import\": \"./public/assets/scripts/choices.mjs\",\n      \"require\": \"./public/assets/scripts/choices.js\",\n      \"style\": \"./public/assets/styles/choices.css\",\n      \"sass\": \"./src/styles/choices.scss\"\n    },\n    \"./search-basic\": {\n      \"types\": \"./public/types/src/index.d.ts\",\n      \"import\": \"./public/assets/scripts/choices.search-basic.mjs\",\n      \"require\": \"./public/assets/scripts/choices.search-basic.min.js\"\n    },\n    \"./search-prefix\": {\n      \"types\": \"./public/types/src/index.d.ts\",\n      \"import\": \"./public/assets/scripts/choices.search-prefix.mjs\",\n      \"require\": \"./public/assets/scripts/choices.search-prefix.min.js\"\n    },\n    \"./search-kmp\": {\n      \"types\": \"./public/types/src/index.d.ts\",\n      \"import\": \"./public/assets/scripts/choices.search-kmp.mjs\",\n      \"require\": \"./public/assets/scripts/choices.search-kmp.min.js\"\n    },\n    \"./search-none\": {\n      \"types\": \"./public/types/src/index.d.ts\",\n      \"import\": \"./public/assets/scripts/choices.search-none.mjs\",\n      \"require\": \"./public/assets/scripts/choices.search-none.min.js\"\n    },\n    \"./public/assets/styles/*.css\": \"./public/assets/styles/*.css\",\n    \"./src/styles/*.scss\": \"./src/styles/*.scss\",\n    \"./src/styles/*\": \"./src/styles/*.scss\"\n  },\n  \"sideEffects\": [\n    \"*.scss\",\n    \"*.css\"\n  ],\n  \"scripts\": {\n    \"start\": \"run-p js:watch css:watch\",\n    \"build\": \"run-p js:build css:build\",\n    \"lint\": \"run-p lint:js lint:scss\",\n    \"lint:js\": \"eslint src/scripts test/scripts test-e2e\",\n    \"lint:scss\": \"stylelint src/**/*.scss\",\n    \"bundlesize\": \"bundlesize\",\n    \"playwright:cli\": \"playwright test --project=chromium\",\n    \"playwright:gui\": \"playwright test --ui  --project=chromium\",\n    \"test\": \"run-s test:unit test:e2e:all\",\n    \"test:unit\": \"vitest run\",\n    \"test:unit:watch\": \"npm run test:unit -- --watch --inspect=5556\",\n    \"test:unit:coverage\": \"vitest run --coverage\",\n    \"test:e2e\": \"run-s playwright:cli\",\n    \"test:e2e:all\": \"playwright test\",\n    \"js:watch\": \"rollup -w --bundleConfigAsCjs -c scripts/rollup.config.mjs --environment TARGET:. --environment OUTPUT_TYPES:umd --environment WATCH_HOST:localhost\",\n    \"js:build\": \"rollup --bundleConfigAsCjs -c scripts/rollup.config.mjs --environment WITH_D_TS_FILES:1 && mv public/assets/scripts/src public/types/\",\n    \"js:build-dev\": \"rollup --bundleConfigAsCjs -c scripts/rollup.config.mjs --environment TARGET:. --environment OUTPUT_TYPES:umd\",\n    \"js:build-dev:esm\": \"rollup --bundleConfigAsCjs -c scripts/rollup.config.mjs --environment TARGET:. --environment OUTPUT_TYPES:mjs\",\n    \"css:watch\": \"nodemon -e scss -x \\\"npm run css:build\\\"\",\n    \"css:build\": \"run-s css:sass css:prefix css:min\",\n    \"css:sass\": \"sass -I scss src/styles/base.scss public/assets/styles/base.css && sass -I scss src/styles/choices.scss public/assets/styles/choices.css\",\n    \"css:prefix\": \"postcss public/assets/styles/*.css --use autoprefixer --no-map --env prod --dir public/assets/styles\",\n    \"css:min\": \"csso public/assets/styles/base.css --output public/assets/styles/base.min.css && csso public/assets/styles/choices.css --output public/assets/styles/choices.min.css\",\n    \"prepublishOnly\": \"npm run build\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/Choices-js/Choices.git\"\n  },\n  \"author\": \"Josh Johnson\",\n  \"license\": \"MIT\",\n  \"files\": [\n    \"public/assets/scripts\",\n    \"public/assets/styles\",\n    \"public/types\",\n    \"src\"\n  ],\n  \"bugs\": {\n    \"url\": \"https://github.com/Choices-js/Choices/issues\"\n  },\n  \"homepage\": \"https://github.com/Choices-js/Choices#readme\",\n  \"keywords\": [\n    \"customisable\",\n    \"input\",\n    \"select\",\n    \"vanilla\",\n    \"plugin\",\n    \"js\"\n  ],\n  \"devDependencies\": {\n    \"@babel/cli\": \"^7.24.8\",\n    \"@babel/core\": \"^7.25.2\",\n    \"@babel/plugin-transform-object-rest-spread\": \"^7.24.7\",\n    \"@babel/preset-env\": \"^7.25.3\",\n    \"@babel/preset-typescript\": \"^7.24.7\",\n    \"@playwright/test\": \"^1.46.0\",\n    \"@rollup/plugin-babel\": \"^6.0.4\",\n    \"@rollup/plugin-node-resolve\": \"^15.2.3\",\n    \"@rollup/plugin-replace\": \"^5.0.7\",\n    \"@rollup/plugin-terser\": \"^1.0.0\",\n    \"@rollup/plugin-typescript\": \"^11.1.6\",\n    \"@types/chai\": \"^4.3.17\",\n    \"@types/node\": \"^22.12.0\",\n    \"@types/sinon\": \"^17.0.3\",\n    \"@types/sinon-chai\": \"^3.2.12\",\n    \"@vitest/coverage-v8\": \"^3.2.4\",\n    \"autoprefixer\": \"^10.4.20\",\n    \"bundlesize2\": \"^0.0.35\",\n    \"chai\": \"^5.1.1\",\n    \"cross-process-lock\": \"^2.1.1\",\n    \"csso-cli\": \"^4.0.2\",\n    \"eslint\": \"^8.57.0\",\n    \"eslint-config-airbnb-base\": \"^15.0.0\",\n    \"eslint-config-airbnb-typescript\": \"^18.0.0\",\n    \"eslint-config-prettier\": \"^9.1.0\",\n    \"eslint-plugin-compat\": \"6.0.0\",\n    \"eslint-plugin-import\": \"^2.29.1\",\n    \"eslint-plugin-prettier\": \"^5.2.1\",\n    \"eslint-plugin-sort-class-members\": \"^1.20.0\",\n    \"eslint-plugin-tree-shaking\": \"^1.12.2\",\n    \"jsdom\": \"^24.1.1\",\n    \"nodemon\": \"^3.1.4\",\n    \"npm-run-all\": \"^4.1.5\",\n    \"postcss\": \"^8.4.41\",\n    \"postcss-cli\": \"^11.0.0\",\n    \"prettier\": \"^3.3.3\",\n    \"rollup\": \"^4.20.0\",\n    \"rollup-plugin-dev\": \"^2.0.5\",\n    \"sass\": \"^1.77.8\",\n    \"sinon\": \"^18.0.0\",\n    \"sinon-chai\": \"^4.0.0\",\n    \"stylelint\": \"^16.7.0\",\n    \"stylelint-config-standard\": \"^36.0.1\",\n    \"stylelint-config-standard-scss\": \"^13.1.0\",\n    \"tslib\": \"^2.6.3\",\n    \"typescript\": \"5.5.x\",\n    \"typescript-eslint\": \"^8.0.1\",\n    \"vitest\": \"^3.2.4\"\n  },\n  \"dependencies\": {\n    \"fuse.js\": \"^7.0.0\"\n  },\n  \"npmName\": \"choices.js\",\n  \"npmFileMap\": [\n    {\n      \"files\": [\n        \"public/assets/scripts/*\",\n        \"public/assets/styles/*\",\n        \"public/types/*\",\n        \"src/icons/*\"\n      ]\n    }\n  ],\n  \"bundlesize\": [\n    {\n      \"path\": \"public/assets/scripts/choices*.min.js\",\n      \"maxSize\": \"25 kB\"\n    },\n    {\n      \"path\": \"public/assets/styles/choices.min.css\",\n      \"maxSize\": \"2.5 kB\"\n    }\n  ]\n}\n"
  },
  {
    "path": "playwright.config.ts",
    "content": "import { defineConfig, devices } from '@playwright/test';\nimport { PlaywrightTestConfig } from 'playwright/types/test';\nimport { BundleTest } from './test-e2e/bundle-test';\n\n/**\n * Read environment variables from file.\n * https://github.com/motdotla/dotenv\n */\n// import dotenv from 'dotenv';\n// dotenv.config({ path: path.resolve(__dirname, '.env') });\n\n/**\n * See https://playwright.dev/docs/test-configuration.\n */\nconst config: PlaywrightTestConfig = {\n  testDir: './test-e2e',\n  snapshotPathTemplate: '{testDir}/__screenshots__/{projectName}-{platform}{ext}',\n  /* Run tests in files in parallel */\n  fullyParallel: true,\n  /* Fail the build on CI if you accidentally left test.only in the source code. */\n  forbidOnly: !!process.env.CI,\n  /* Retry on CI only */\n  retries: 0,\n  /* Opt out of parallel tests on CI. */\n  workers: process.env.CI ? 1 : undefined,\n  /* Reporter to use. See https://playwright.dev/docs/test-reporters */\n  reporter: process.env.CI ? [['github'], ['html', { open: 'never' }]] : 'line',\n  timeout: process.env.CI ? 5000 : 1000,\n  expect : {\n    timeout: process.env.CI ? 1000 : 500,\n  },\n  /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */\n  use: {\n    /* Base URL to use in actions like `await page.goto('/')`. */\n    baseURL: 'http://localhost:3001/',\n\n    /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */\n    trace: 'on-first-retry',\n\n    testIdAttribute: 'data-test-hook',\n  },\n\n  /* Configure projects for major browsers */\n  projects: [\n    {\n      name: 'chromium',\n      use: {\n        ...devices['Desktop Chrome'],\n        contextOptions: {\n          // chromium-specific permissions\n          permissions: ['clipboard-read', 'clipboard-write'],\n        },\n      },\n    },\n    {\n      name: 'firefox',\n      use: { ...devices['Desktop Firefox'] },\n    },\n    {\n      name: 'webkit',\n      use: { ...devices['Desktop Safari'] },\n    },\n\n    /* Test against mobile viewports. */\n    // {\n    //   name: 'Mobile Chrome',\n    //   use: { ...devices['Pixel 5'] },\n    // },\n    // {\n    //   name: 'Mobile Safari',\n    //   use: { ...devices['iPhone 12'] },\n    // },\n\n    /* Test against branded browsers. */\n    // {\n    //   name: 'Microsoft Edge',\n    //   use: { ...devices['Desktop Edge'], channel: 'msedge' },\n    // },\n    // {\n    //   name: 'Google Chrome',\n    //   use: { ...devices['Desktop Chrome'], channel: 'chrome' },\n    // },\n  ],\n\n  /* Run your local dev server before starting the tests */\n  webServer: {\n    command: 'npm run start',\n    url: 'http://localhost:3001',\n    reuseExistingServer: !process.env.CI,\n  },\n};\n\nconst bundles = [\n  {\n    name: '',\n    bundle: process.env.CI ? '/assets/scripts/choices.min.js' : '/assets/scripts/choices.js',\n    enabled: true,\n  },\n];\nconst projects = config.projects;\nif (config.use.baseURL) {\n  config.projects = [];\n\n  projects.forEach((project) => {\n    bundles.forEach(({ name, bundle, enabled }) => {\n      if (!enabled) {\n        return;\n      }\n      const projectBundle = {\n        ...project,\n        name: project.name + name,\n        use: {\n          ...project.use,\n          bundle: config.use.baseURL + bundle,\n        }\n      };\n      config.projects.push(projectBundle);\n    });\n  });\n}\n\nexport default defineConfig<BundleTest>(config);"
  },
  {
    "path": "public/assets/images/browserconfig.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<browserconfig>\n  <msapplication>\n    <tile>\n      <square150x150logo src=\"/assets/images/mstile-150x150.png\"/>\n      <TileColor>#ffffff</TileColor>\n    </tile>\n  </msapplication>\n</browserconfig>\n"
  },
  {
    "path": "public/assets/images/manifest.json",
    "content": "{\n\t\"name\": \"Choices.js\",\n\t\"icons\": [\n\t\t{\n\t\t\t\"src\": \"\\/assets\\/images\\/android-chrome-192x192.png\",\n\t\t\t\"sizes\": \"192x192\",\n\t\t\t\"type\": \"image\\/png\"\n\t\t}\n\t],\n\t\"theme_color\": \"#ffffff\",\n\t\"display\": \"standalone\"\n}\n"
  },
  {
    "path": "public/assets/scripts/choices.js",
    "content": "/*! choices.js v11.2.1 | © 2026 Josh Johnson | https://github.com/Choices-js/Choices#readme */\n\n(function (global, factory) {\n    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :\n    typeof define === 'function' && define.amd ? define(factory) :\n    (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Choices = factory());\n})(this, (function () { 'use strict';\n\n    /******************************************************************************\n    Copyright (c) Microsoft Corporation.\n\n    Permission to use, copy, modify, and/or distribute this software for any\n    purpose with or without fee is hereby granted.\n\n    THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\n    REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\n    AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\n    INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\n    LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\n    OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\n    PERFORMANCE OF THIS SOFTWARE.\n    ***************************************************************************** */\n    /* global Reflect, Promise, SuppressedError, Symbol */\n\n    var extendStatics = function (d, b) {\n      extendStatics = Object.setPrototypeOf || {\n        __proto__: []\n      } instanceof Array && function (d, b) {\n        d.__proto__ = b;\n      } || function (d, b) {\n        for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p];\n      };\n      return extendStatics(d, b);\n    };\n    function __extends(d, b) {\n      if (typeof b !== \"function\" && b !== null) throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\n      extendStatics(d, b);\n      function __() {\n        this.constructor = d;\n      }\n      d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\n    }\n    var __assign = function () {\n      __assign = Object.assign || function __assign(t) {\n        for (var s, i = 1, n = arguments.length; i < n; i++) {\n          s = arguments[i];\n          for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\n        }\n        return t;\n      };\n      return __assign.apply(this, arguments);\n    };\n    function __spreadArray(to, from, pack) {\n      if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\n        if (ar || !(i in from)) {\n          if (!ar) ar = Array.prototype.slice.call(from, 0, i);\n          ar[i] = from[i];\n        }\n      }\n      return to.concat(ar || Array.prototype.slice.call(from));\n    }\n    typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\n      var e = new Error(message);\n      return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\n    };\n\n    var ActionType = {\n        ADD_CHOICE: 'ADD_CHOICE',\n        REMOVE_CHOICE: 'REMOVE_CHOICE',\n        FILTER_CHOICES: 'FILTER_CHOICES',\n        ACTIVATE_CHOICES: 'ACTIVATE_CHOICES',\n        CLEAR_CHOICES: 'CLEAR_CHOICES',\n        ADD_GROUP: 'ADD_GROUP',\n        ADD_ITEM: 'ADD_ITEM',\n        REMOVE_ITEM: 'REMOVE_ITEM',\n        HIGHLIGHT_ITEM: 'HIGHLIGHT_ITEM',\n    };\n\n    var EventType = {\n        showDropdown: 'showDropdown',\n        hideDropdown: 'hideDropdown',\n        change: 'change',\n        choice: 'choice',\n        search: 'search',\n        addItem: 'addItem',\n        removeItem: 'removeItem',\n        highlightItem: 'highlightItem',\n        highlightChoice: 'highlightChoice',\n        unhighlightItem: 'unhighlightItem',\n    };\n\n    var KeyCodeMap = {\n        TAB_KEY: 9,\n        SHIFT_KEY: 16,\n        BACK_KEY: 46,\n        DELETE_KEY: 8,\n        ENTER_KEY: 13,\n        A_KEY: 65,\n        ESC_KEY: 27,\n        UP_KEY: 38,\n        DOWN_KEY: 40,\n        PAGE_UP_KEY: 33,\n        PAGE_DOWN_KEY: 34,\n    };\n\n    var ObjectsInConfig = ['fuseOptions', 'classNames'];\n\n    var PassedElementTypes = {\n        Text: 'text',\n        SelectOne: 'select-one',\n        SelectMultiple: 'select-multiple',\n    };\n\n    var addChoice = function (choice) { return ({\n        type: ActionType.ADD_CHOICE,\n        choice: choice,\n    }); };\n    var removeChoice = function (choice) { return ({\n        type: ActionType.REMOVE_CHOICE,\n        choice: choice,\n    }); };\n    var filterChoices = function (results) { return ({\n        type: ActionType.FILTER_CHOICES,\n        results: results,\n    }); };\n    var activateChoices = function (active) {\n        return ({\n            type: ActionType.ACTIVATE_CHOICES,\n            active: active,\n        });\n    };\n\n    var addGroup = function (group) { return ({\n        type: ActionType.ADD_GROUP,\n        group: group,\n    }); };\n\n    var addItem = function (item) { return ({\n        type: ActionType.ADD_ITEM,\n        item: item,\n    }); };\n    var removeItem$1 = function (item) { return ({\n        type: ActionType.REMOVE_ITEM,\n        item: item,\n    }); };\n    var highlightItem = function (item, highlighted) { return ({\n        type: ActionType.HIGHLIGHT_ITEM,\n        item: item,\n        highlighted: highlighted,\n    }); };\n\n    var getRandomNumber = function (min, max) { return Math.floor(Math.random() * (max - min) + min); };\n    var generateChars = function (length) {\n        return Array.from({ length: length }, function () { return getRandomNumber(0, 36).toString(36); }).join('');\n    };\n    var generateId = function (element, prefix) {\n        var id = element.id || (element.name && \"\".concat(element.name, \"-\").concat(generateChars(2))) || generateChars(4);\n        id = id.replace(/(:|\\.|\\[|\\]|,)/g, '');\n        id = \"\".concat(prefix, \"-\").concat(id);\n        return id;\n    };\n    var getAdjacentEl = function (startEl, selector, direction) {\n        if (direction === void 0) { direction = 1; }\n        var prop = \"\".concat(direction > 0 ? 'next' : 'previous', \"ElementSibling\");\n        var sibling = startEl[prop];\n        while (sibling) {\n            if (sibling.matches(selector)) {\n                return sibling;\n            }\n            sibling = sibling[prop];\n        }\n        return null;\n    };\n    var isScrolledIntoView = function (element, parent, direction) {\n        if (direction === void 0) { direction = 1; }\n        var isVisible;\n        if (direction > 0) {\n            // In view from bottom\n            isVisible = parent.scrollTop + parent.offsetHeight >= element.offsetTop + element.offsetHeight;\n        }\n        else {\n            // In view from top\n            isVisible = element.offsetTop >= parent.scrollTop;\n        }\n        return isVisible;\n    };\n    var sanitise = function (value) {\n        if (typeof value !== 'string') {\n            if (value === null || value === undefined) {\n                return '';\n            }\n            if (typeof value === 'object') {\n                if ('raw' in value) {\n                    return sanitise(value.raw);\n                }\n                if ('trusted' in value) {\n                    return value.trusted;\n                }\n            }\n            return value;\n        }\n        return value\n            .replace(/&/g, '&amp;')\n            .replace(/>/g, '&gt;')\n            .replace(/</g, '&lt;')\n            .replace(/'/g, '&#039;')\n            .replace(/\"/g, '&quot;');\n    };\n    var strToEl = (function () {\n        var tmpEl = document.createElement('div');\n        return function (str) {\n            tmpEl.innerHTML = str.trim();\n            var firstChild = tmpEl.children[0];\n            while (tmpEl.firstChild) {\n                tmpEl.removeChild(tmpEl.firstChild);\n            }\n            return firstChild;\n        };\n    })();\n    var resolveStringFunction = function (fn) {\n        return typeof fn === 'function' ? fn() : fn;\n    };\n    var unwrapStringForRaw = function (s) {\n        if (typeof s === 'string') {\n            return s;\n        }\n        if (typeof s === 'object') {\n            if ('trusted' in s) {\n                return s.trusted;\n            }\n            if ('raw' in s) {\n                return s.raw;\n            }\n        }\n        return '';\n    };\n    var unwrapStringForEscaped = function (s) {\n        if (typeof s === 'string') {\n            return s;\n        }\n        if (typeof s === 'object') {\n            if ('escaped' in s) {\n                return s.escaped;\n            }\n            if ('trusted' in s) {\n                return s.trusted;\n            }\n        }\n        return '';\n    };\n    var getChoiceForOutput = function (choice, keyCode) {\n        return {\n            id: choice.id,\n            highlighted: choice.highlighted,\n            labelClass: choice.labelClass,\n            labelDescription: unwrapStringForRaw(choice.labelDescription),\n            customProperties: choice.customProperties,\n            disabled: choice.disabled,\n            active: choice.active,\n            label: choice.label,\n            placeholder: choice.placeholder,\n            value: choice.value,\n            groupValue: choice.group ? choice.group.label : undefined,\n            element: choice.element,\n            keyCode: keyCode,\n        };\n    };\n    var resolveNoticeFunction = function (fn, value, item) {\n        return typeof fn === 'function' ? fn(sanitise(value), unwrapStringForRaw(value), item) : fn;\n    };\n    var escapeForTemplate = function (allowHTML, s) {\n        return allowHTML ? unwrapStringForEscaped(s) : sanitise(s);\n    };\n    var setElementHtml = function (el, allowHtml, html) {\n        el.innerHTML = escapeForTemplate(allowHtml, html);\n    };\n    var sortByAlpha = function (_a, _b) {\n        var value = _a.value, _c = _a.label, label = _c === void 0 ? value : _c;\n        var value2 = _b.value, _d = _b.label, label2 = _d === void 0 ? value2 : _d;\n        return unwrapStringForRaw(label).localeCompare(unwrapStringForRaw(label2), [], {\n            sensitivity: 'base',\n            ignorePunctuation: true,\n            numeric: true,\n        });\n    };\n    var sortByRank = function (a, b) {\n        return a.rank - b.rank;\n    };\n    var dispatchEvent = function (element, type, customArgs) {\n        if (customArgs === void 0) { customArgs = null; }\n        var event = new CustomEvent(type, {\n            detail: customArgs,\n            bubbles: true,\n            cancelable: true,\n        });\n        return element.dispatchEvent(event);\n    };\n    /**\n     * Returns an array of keys present on the first but missing on the second object\n     */\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    var diff = function (a, b) {\n        var aKeys = Object.keys(a).sort();\n        var bKeys = Object.keys(b).sort();\n        return aKeys.filter(function (i) { return bKeys.indexOf(i) < 0; });\n    };\n    var getClassNames = function (ClassNames) {\n        return Array.isArray(ClassNames) ? ClassNames : [ClassNames];\n    };\n    var getClassNamesSelector = function (option) {\n        if (option && Array.isArray(option)) {\n            return option\n                .map(function (item) {\n                return \".\".concat(item);\n            })\n                .join('');\n        }\n        return \".\".concat(option);\n    };\n    var addClassesToElement = function (element, className) {\n        var _a;\n        (_a = element.classList).add.apply(_a, getClassNames(className));\n    };\n    var removeClassesFromElement = function (element, className) {\n        var _a;\n        (_a = element.classList).remove.apply(_a, getClassNames(className));\n    };\n    var parseCustomProperties = function (customProperties) {\n        if (typeof customProperties !== 'undefined') {\n            try {\n                return JSON.parse(customProperties);\n            }\n            catch (e) {\n                return customProperties;\n            }\n        }\n        return {};\n    };\n    var updateClassList = function (item, add, remove) {\n        var itemEl = item.itemEl;\n        if (itemEl) {\n            removeClassesFromElement(itemEl, remove);\n            addClassesToElement(itemEl, add);\n        }\n    };\n\n    var Dropdown = /** @class */ (function () {\n        function Dropdown(_a) {\n            var element = _a.element, type = _a.type, classNames = _a.classNames;\n            this.element = element;\n            this.classNames = classNames;\n            this.type = type;\n            this.isActive = false;\n        }\n        /**\n         * Show dropdown to user by adding active state class\n         */\n        Dropdown.prototype.show = function () {\n            addClassesToElement(this.element, this.classNames.activeState);\n            this.element.setAttribute('aria-expanded', 'true');\n            this.isActive = true;\n            return this;\n        };\n        /**\n         * Hide dropdown from user\n         */\n        Dropdown.prototype.hide = function () {\n            removeClassesFromElement(this.element, this.classNames.activeState);\n            this.element.setAttribute('aria-expanded', 'false');\n            this.isActive = false;\n            return this;\n        };\n        return Dropdown;\n    }());\n\n    var Container = /** @class */ (function () {\n        function Container(_a) {\n            var element = _a.element, type = _a.type, classNames = _a.classNames, position = _a.position;\n            this.element = element;\n            this.classNames = classNames;\n            this.type = type;\n            this.position = position;\n            this.isOpen = false;\n            this.isFlipped = false;\n            this.isDisabled = false;\n            this.isLoading = false;\n        }\n        /**\n         * Determine whether container should be flipped based on passed\n         * dropdown position\n         */\n        Container.prototype.shouldFlip = function (dropdownPos, dropdownHeight) {\n            // If flip is enabled and the dropdown bottom position is\n            // greater than the window height flip the dropdown.\n            var shouldFlip = false;\n            if (this.position === 'auto') {\n                shouldFlip =\n                    this.element.getBoundingClientRect().top - dropdownHeight >= 0 &&\n                        !window.matchMedia(\"(min-height: \".concat(dropdownPos + 1, \"px)\")).matches;\n            }\n            else if (this.position === 'top') {\n                shouldFlip = true;\n            }\n            return shouldFlip;\n        };\n        Container.prototype.setActiveDescendant = function (activeDescendantID) {\n            this.element.setAttribute('aria-activedescendant', activeDescendantID);\n        };\n        Container.prototype.removeActiveDescendant = function () {\n            this.element.removeAttribute('aria-activedescendant');\n        };\n        Container.prototype.open = function (dropdownPos, dropdownHeight) {\n            addClassesToElement(this.element, this.classNames.openState);\n            this.element.setAttribute('aria-expanded', 'true');\n            this.isOpen = true;\n            if (this.shouldFlip(dropdownPos, dropdownHeight)) {\n                addClassesToElement(this.element, this.classNames.flippedState);\n                this.isFlipped = true;\n            }\n        };\n        Container.prototype.close = function () {\n            removeClassesFromElement(this.element, this.classNames.openState);\n            this.element.setAttribute('aria-expanded', 'false');\n            this.removeActiveDescendant();\n            this.isOpen = false;\n            // A dropdown flips if it does not have space within the page\n            if (this.isFlipped) {\n                removeClassesFromElement(this.element, this.classNames.flippedState);\n                this.isFlipped = false;\n            }\n        };\n        Container.prototype.addFocusState = function () {\n            addClassesToElement(this.element, this.classNames.focusState);\n        };\n        Container.prototype.removeFocusState = function () {\n            removeClassesFromElement(this.element, this.classNames.focusState);\n        };\n        Container.prototype.addInvalidState = function () {\n            addClassesToElement(this.element, this.classNames.invalidState);\n        };\n        Container.prototype.removeInvalidState = function () {\n            removeClassesFromElement(this.element, this.classNames.invalidState);\n        };\n        Container.prototype.enable = function () {\n            removeClassesFromElement(this.element, this.classNames.disabledState);\n            this.element.removeAttribute('aria-disabled');\n            if (this.type === PassedElementTypes.SelectOne) {\n                this.element.setAttribute('tabindex', '0');\n            }\n            this.isDisabled = false;\n        };\n        Container.prototype.disable = function () {\n            addClassesToElement(this.element, this.classNames.disabledState);\n            this.element.setAttribute('aria-disabled', 'true');\n            if (this.type === PassedElementTypes.SelectOne) {\n                this.element.setAttribute('tabindex', '-1');\n            }\n            this.isDisabled = true;\n        };\n        Container.prototype.wrap = function (element) {\n            var el = this.element;\n            var parentNode = element.parentNode;\n            if (parentNode) {\n                if (element.nextSibling) {\n                    parentNode.insertBefore(el, element.nextSibling);\n                }\n                else {\n                    parentNode.appendChild(el);\n                }\n            }\n            el.appendChild(element);\n        };\n        Container.prototype.unwrap = function (element) {\n            var el = this.element;\n            var parentNode = el.parentNode;\n            if (parentNode) {\n                // Move passed element outside this element\n                parentNode.insertBefore(element, el);\n                // Remove this element\n                parentNode.removeChild(el);\n            }\n        };\n        Container.prototype.addLoadingState = function () {\n            addClassesToElement(this.element, this.classNames.loadingState);\n            this.element.setAttribute('aria-busy', 'true');\n            this.isLoading = true;\n        };\n        Container.prototype.removeLoadingState = function () {\n            removeClassesFromElement(this.element, this.classNames.loadingState);\n            this.element.removeAttribute('aria-busy');\n            this.isLoading = false;\n        };\n        return Container;\n    }());\n\n    var Input = /** @class */ (function () {\n        function Input(_a) {\n            var element = _a.element, type = _a.type, classNames = _a.classNames, preventPaste = _a.preventPaste;\n            this.element = element;\n            this.type = type;\n            this.classNames = classNames;\n            this.preventPaste = preventPaste;\n            this.isFocussed = this.element.isEqualNode(document.activeElement);\n            this.isDisabled = element.disabled;\n            this._onPaste = this._onPaste.bind(this);\n            this._onInput = this._onInput.bind(this);\n            this._onFocus = this._onFocus.bind(this);\n            this._onBlur = this._onBlur.bind(this);\n        }\n        Object.defineProperty(Input.prototype, \"placeholder\", {\n            set: function (placeholder) {\n                this.element.placeholder = placeholder;\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(Input.prototype, \"value\", {\n            get: function () {\n                return this.element.value;\n            },\n            set: function (value) {\n                this.element.value = value;\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Input.prototype.addEventListeners = function () {\n            var el = this.element;\n            el.addEventListener('paste', this._onPaste);\n            el.addEventListener('input', this._onInput, {\n                passive: true,\n            });\n            el.addEventListener('focus', this._onFocus, {\n                passive: true,\n            });\n            el.addEventListener('blur', this._onBlur, {\n                passive: true,\n            });\n        };\n        Input.prototype.removeEventListeners = function () {\n            var el = this.element;\n            el.removeEventListener('input', this._onInput);\n            el.removeEventListener('paste', this._onPaste);\n            el.removeEventListener('focus', this._onFocus);\n            el.removeEventListener('blur', this._onBlur);\n        };\n        Input.prototype.enable = function () {\n            var el = this.element;\n            el.removeAttribute('disabled');\n            this.isDisabled = false;\n        };\n        Input.prototype.disable = function () {\n            var el = this.element;\n            el.setAttribute('disabled', '');\n            this.isDisabled = true;\n        };\n        Input.prototype.focus = function () {\n            if (!this.isFocussed) {\n                this.element.focus();\n            }\n        };\n        Input.prototype.blur = function () {\n            if (this.isFocussed) {\n                this.element.blur();\n            }\n        };\n        Input.prototype.clear = function (setWidth) {\n            if (setWidth === void 0) { setWidth = true; }\n            this.element.value = '';\n            if (setWidth) {\n                this.setWidth();\n            }\n            return this;\n        };\n        /**\n         * Set the correct input width based on placeholder\n         * value or input value\n         */\n        Input.prototype.setWidth = function () {\n            // Resize input to contents or placeholder\n            var element = this.element;\n            element.style.minWidth = \"\".concat(element.placeholder.length + 1, \"ch\");\n            element.style.width = \"\".concat(element.value.length + 1, \"ch\");\n        };\n        Input.prototype.setActiveDescendant = function (activeDescendantID) {\n            this.element.setAttribute('aria-activedescendant', activeDescendantID);\n        };\n        Input.prototype.removeActiveDescendant = function () {\n            this.element.removeAttribute('aria-activedescendant');\n        };\n        Input.prototype._onInput = function () {\n            if (this.type !== PassedElementTypes.SelectOne) {\n                this.setWidth();\n            }\n        };\n        Input.prototype._onPaste = function (event) {\n            if (this.preventPaste) {\n                event.preventDefault();\n            }\n        };\n        Input.prototype._onFocus = function () {\n            this.isFocussed = true;\n        };\n        Input.prototype._onBlur = function () {\n            this.isFocussed = false;\n        };\n        return Input;\n    }());\n\n    var SCROLLING_SPEED = 4;\n\n    var List = /** @class */ (function () {\n        function List(_a) {\n            var element = _a.element;\n            this.element = element;\n            this.scrollPos = this.element.scrollTop;\n            this.height = this.element.offsetHeight;\n        }\n        List.prototype.prepend = function (node) {\n            var child = this.element.firstElementChild;\n            if (child) {\n                this.element.insertBefore(node, child);\n            }\n            else {\n                this.element.append(node);\n            }\n        };\n        List.prototype.scrollToTop = function () {\n            this.element.scrollTop = 0;\n        };\n        List.prototype.scrollToChildElement = function (element, direction) {\n            var _this = this;\n            if (!element) {\n                return;\n            }\n            var listHeight = this.element.offsetHeight;\n            // Scroll position of dropdown\n            var listScrollPosition = this.element.scrollTop + listHeight;\n            var elementHeight = element.offsetHeight;\n            // Distance from bottom of element to top of parent\n            var elementPos = element.offsetTop + elementHeight;\n            // Difference between the element and scroll position\n            var destination = direction > 0 ? this.element.scrollTop + elementPos - listScrollPosition : element.offsetTop;\n            requestAnimationFrame(function () {\n                _this._animateScroll(destination, direction);\n            });\n        };\n        List.prototype._scrollDown = function (scrollPos, strength, destination) {\n            var easing = (destination - scrollPos) / strength;\n            var distance = easing > 1 ? easing : 1;\n            this.element.scrollTop = scrollPos + distance;\n        };\n        List.prototype._scrollUp = function (scrollPos, strength, destination) {\n            var easing = (scrollPos - destination) / strength;\n            var distance = easing > 1 ? easing : 1;\n            this.element.scrollTop = scrollPos - distance;\n        };\n        List.prototype._animateScroll = function (destination, direction) {\n            var _this = this;\n            var strength = SCROLLING_SPEED;\n            var choiceListScrollTop = this.element.scrollTop;\n            var continueAnimation = false;\n            if (direction > 0) {\n                this._scrollDown(choiceListScrollTop, strength, destination);\n                if (choiceListScrollTop < destination) {\n                    continueAnimation = true;\n                }\n            }\n            else {\n                this._scrollUp(choiceListScrollTop, strength, destination);\n                if (choiceListScrollTop > destination) {\n                    continueAnimation = true;\n                }\n            }\n            if (continueAnimation) {\n                requestAnimationFrame(function () {\n                    _this._animateScroll(destination, direction);\n                });\n            }\n        };\n        return List;\n    }());\n\n    var WrappedElement = /** @class */ (function () {\n        function WrappedElement(_a) {\n            var element = _a.element, classNames = _a.classNames;\n            this.element = element;\n            this.classNames = classNames;\n            this.isDisabled = false;\n        }\n        Object.defineProperty(WrappedElement.prototype, \"isActive\", {\n            get: function () {\n                return this.element.dataset.choice === 'active';\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(WrappedElement.prototype, \"dir\", {\n            get: function () {\n                return this.element.dir;\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(WrappedElement.prototype, \"value\", {\n            get: function () {\n                return this.element.value;\n            },\n            set: function (value) {\n                this.element.setAttribute('value', value);\n                this.element.value = value;\n            },\n            enumerable: false,\n            configurable: true\n        });\n        WrappedElement.prototype.conceal = function () {\n            var el = this.element;\n            // Hide passed input\n            addClassesToElement(el, this.classNames.input);\n            el.hidden = true;\n            // Remove element from tab index\n            el.tabIndex = -1;\n            // Backup original styles if any\n            var origStyle = el.getAttribute('style');\n            if (origStyle) {\n                el.setAttribute('data-choice-orig-style', origStyle);\n            }\n            el.setAttribute('data-choice', 'active');\n        };\n        WrappedElement.prototype.reveal = function () {\n            var el = this.element;\n            // Reinstate passed element\n            removeClassesFromElement(el, this.classNames.input);\n            el.hidden = false;\n            el.removeAttribute('tabindex');\n            // Recover original styles if any\n            var origStyle = el.getAttribute('data-choice-orig-style');\n            if (origStyle) {\n                el.removeAttribute('data-choice-orig-style');\n                el.setAttribute('style', origStyle);\n            }\n            else {\n                el.removeAttribute('style');\n            }\n            el.removeAttribute('data-choice');\n        };\n        WrappedElement.prototype.enable = function () {\n            this.element.removeAttribute('disabled');\n            this.element.disabled = false;\n            this.isDisabled = false;\n        };\n        WrappedElement.prototype.disable = function () {\n            this.element.setAttribute('disabled', '');\n            this.element.disabled = true;\n            this.isDisabled = true;\n        };\n        WrappedElement.prototype.triggerEvent = function (eventType, data) {\n            dispatchEvent(this.element, eventType, data || {});\n        };\n        return WrappedElement;\n    }());\n\n    var WrappedInput = /** @class */ (function (_super) {\n        __extends(WrappedInput, _super);\n        function WrappedInput() {\n            return _super !== null && _super.apply(this, arguments) || this;\n        }\n        return WrappedInput;\n    }(WrappedElement));\n\n    var coerceBool = function (arg, defaultValue) {\n        if (defaultValue === void 0) { defaultValue = true; }\n        return typeof arg === 'undefined' ? defaultValue : !!arg;\n    };\n    var stringToHtmlClass = function (input) {\n        if (typeof input === 'string') {\n            // eslint-disable-next-line no-param-reassign\n            input = input.split(' ').filter(function (s) { return s.length; });\n        }\n        if (Array.isArray(input) && input.length) {\n            return input;\n        }\n        return undefined;\n    };\n    var mapInputToChoice = function (value, allowGroup, allowRawString) {\n        if (allowRawString === void 0) { allowRawString = true; }\n        if (typeof value === 'string') {\n            var sanitisedValue = sanitise(value);\n            var userValue = allowRawString || sanitisedValue === value ? value : { escaped: sanitisedValue, raw: value };\n            var result_1 = mapInputToChoice({\n                value: value,\n                label: userValue,\n                selected: true,\n            }, false);\n            return result_1;\n        }\n        var groupOrChoice = value;\n        if ('choices' in groupOrChoice) {\n            if (!allowGroup) {\n                // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/optgroup\n                throw new TypeError(\"optGroup is not allowed\");\n            }\n            var group = groupOrChoice;\n            var choices = group.choices.map(function (e) { return mapInputToChoice(e, false); });\n            var result_2 = {\n                id: 0, // actual ID will be assigned during _addGroup\n                label: unwrapStringForRaw(group.label) || group.value,\n                active: !!choices.length,\n                disabled: !!group.disabled,\n                choices: choices,\n            };\n            return result_2;\n        }\n        var choice = groupOrChoice;\n        var result = {\n            id: 0, // actual ID will be assigned during _addChoice\n            group: null, // actual group will be assigned during _addGroup but before _addChoice\n            score: 0, // used in search\n            rank: 0, // used in search, stable sort order\n            value: choice.value,\n            label: choice.label || choice.value,\n            active: coerceBool(choice.active),\n            selected: coerceBool(choice.selected, false),\n            disabled: coerceBool(choice.disabled, false),\n            placeholder: coerceBool(choice.placeholder, false),\n            highlighted: false,\n            labelClass: stringToHtmlClass(choice.labelClass),\n            labelDescription: choice.labelDescription,\n            customProperties: choice.customProperties,\n        };\n        return result;\n    };\n\n    var isHtmlInputElement = function (e) { return e.tagName === 'INPUT'; };\n    var isHtmlSelectElement = function (e) { return e.tagName === 'SELECT'; };\n    var isHtmlOption = function (e) { return e.tagName === 'OPTION'; };\n    var isHtmlOptgroup = function (e) { return e.tagName === 'OPTGROUP'; };\n\n    var WrappedSelect = /** @class */ (function (_super) {\n        __extends(WrappedSelect, _super);\n        function WrappedSelect(_a) {\n            var element = _a.element, classNames = _a.classNames, template = _a.template, extractPlaceholder = _a.extractPlaceholder;\n            var _this = _super.call(this, { element: element, classNames: classNames }) || this;\n            _this.template = template;\n            _this.extractPlaceholder = extractPlaceholder;\n            return _this;\n        }\n        Object.defineProperty(WrappedSelect.prototype, \"placeholderOption\", {\n            get: function () {\n                return (this.element.querySelector('option[value=\"\"]') ||\n                    // Backward compatibility layer for the non-standard placeholder attribute supported in older versions.\n                    this.element.querySelector('option[placeholder]'));\n            },\n            enumerable: false,\n            configurable: true\n        });\n        WrappedSelect.prototype.addOptions = function (choices) {\n            var _this = this;\n            var fragment = document.createDocumentFragment();\n            choices.forEach(function (obj) {\n                var choice = obj;\n                if (choice.element) {\n                    return;\n                }\n                var option = _this.template(choice);\n                fragment.appendChild(option);\n                choice.element = option;\n            });\n            this.element.appendChild(fragment);\n        };\n        WrappedSelect.prototype.optionsAsChoices = function () {\n            var _this = this;\n            var choices = [];\n            this.element.querySelectorAll(':scope > option, :scope > optgroup').forEach(function (e) {\n                if (isHtmlOption(e)) {\n                    choices.push(_this._optionToChoice(e));\n                }\n                else if (isHtmlOptgroup(e)) {\n                    choices.push(_this._optgroupToChoice(e));\n                }\n                // todo: hr as empty optgroup, requires displaying empty opt-groups to be useful\n            });\n            return choices;\n        };\n        // eslint-disable-next-line class-methods-use-this\n        WrappedSelect.prototype._optionToChoice = function (option) {\n            // option.value returns the label if there is no value attribute, which can break legacy placeholder attribute support\n            if (!option.hasAttribute('value') && option.hasAttribute('placeholder')) {\n                option.setAttribute('value', '');\n                option.value = '';\n            }\n            return {\n                id: 0,\n                group: null,\n                score: 0,\n                rank: 0,\n                value: option.value,\n                // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/option\n                // This attribute is text for the label indicating the meaning of the option. If the `label` attribute isn't defined, its value is that of the element text content (ie `innerText`).\n                label: option.label,\n                element: option,\n                active: true,\n                // this returns true if nothing is selected on initial load, which will break placeholder support\n                selected: this.extractPlaceholder ? option.selected : option.hasAttribute('selected'),\n                disabled: option.disabled,\n                highlighted: false,\n                placeholder: this.extractPlaceholder && (!option.value || option.hasAttribute('placeholder')),\n                labelClass: typeof option.dataset.labelClass !== 'undefined' ? stringToHtmlClass(option.dataset.labelClass) : undefined,\n                labelDescription: typeof option.dataset.labelDescription !== 'undefined'\n                    ? { trusted: option.dataset.labelDescription }\n                    : undefined,\n                customProperties: parseCustomProperties(option.dataset.customProperties),\n            };\n        };\n        WrappedSelect.prototype._optgroupToChoice = function (optgroup) {\n            var _this = this;\n            var options = optgroup.querySelectorAll('option');\n            var choices = Array.from(options).map(function (option) { return _this._optionToChoice(option); });\n            return {\n                id: 0,\n                label: optgroup.label || '',\n                element: optgroup,\n                active: !!choices.length,\n                disabled: optgroup.disabled,\n                choices: choices,\n            };\n        };\n        return WrappedSelect;\n    }(WrappedElement));\n\n    var DEFAULT_CLASSNAMES = {\n        containerOuter: ['choices'],\n        containerInner: ['choices__inner'],\n        input: ['choices__input'],\n        inputCloned: ['choices__input--cloned'],\n        list: ['choices__list'],\n        listItems: ['choices__list--multiple'],\n        listSingle: ['choices__list--single'],\n        listDropdown: ['choices__list--dropdown'],\n        item: ['choices__item'],\n        itemSelectable: ['choices__item--selectable'],\n        itemDisabled: ['choices__item--disabled'],\n        itemChoice: ['choices__item--choice'],\n        description: ['choices__description'],\n        placeholder: ['choices__placeholder'],\n        group: ['choices__group'],\n        groupHeading: ['choices__heading'],\n        button: ['choices__button'],\n        activeState: ['is-active'],\n        focusState: ['is-focused'],\n        openState: ['is-open'],\n        disabledState: ['is-disabled'],\n        highlightedState: ['is-highlighted'],\n        selectedState: ['is-selected'],\n        flippedState: ['is-flipped'],\n        loadingState: ['is-loading'],\n        invalidState: ['is-invalid'],\n        notice: ['choices__notice'],\n        addChoice: ['choices__item--selectable', 'add-choice'],\n        noResults: ['has-no-results'],\n        noChoices: ['has-no-choices'],\n    };\n    var DEFAULT_CONFIG = {\n        items: [],\n        choices: [],\n        silent: false,\n        renderChoiceLimit: -1,\n        maxItemCount: -1,\n        closeDropdownOnSelect: 'auto',\n        singleModeForMultiSelect: false,\n        addChoices: false,\n        addItems: true,\n        addItemFilter: function (value) { return !!value && value !== ''; },\n        removeItems: true,\n        removeItemButton: false,\n        removeItemButtonAlignLeft: false,\n        editItems: false,\n        allowHTML: false,\n        allowHtmlUserInput: false,\n        duplicateItemsAllowed: true,\n        delimiter: ',',\n        paste: true,\n        searchEnabled: true,\n        searchChoices: true,\n        searchDisabledChoices: false,\n        searchFloor: 1,\n        searchResultLimit: 4,\n        searchFields: ['label', 'value'],\n        position: 'auto',\n        resetScrollPosition: true,\n        shouldSort: true,\n        shouldSortItems: false,\n        sorter: sortByAlpha,\n        shadowRoot: null,\n        placeholder: true,\n        placeholderValue: null,\n        searchPlaceholderValue: null,\n        prependValue: null,\n        appendValue: null,\n        renderSelectedChoices: 'auto',\n        searchRenderSelectedChoices: true,\n        loadingText: 'Loading...',\n        noResultsText: 'No results found',\n        noChoicesText: 'No choices to choose from',\n        itemSelectText: 'Press to select',\n        uniqueItemText: 'Only unique values can be added',\n        customAddItemText: 'Only values matching specific conditions can be added',\n        addItemText: function (value) { return \"Press Enter to add <b>\\\"\".concat(value, \"\\\"</b>\"); },\n        removeItemIconText: function () { return \"Remove item\"; },\n        removeItemLabelText: function (value, _valueRaw, i) {\n            return \"Remove item: \".concat(i ? sanitise(i.label) : value);\n        },\n        maxItemText: function (maxItemCount) { return \"Only \".concat(maxItemCount, \" values can be added\"); },\n        valueComparer: function (value1, value2) { return value1 === value2; },\n        fuseOptions: {\n            includeScore: true,\n        },\n        labelId: '',\n        callbackOnInit: null,\n        callbackOnCreateTemplates: null,\n        classNames: DEFAULT_CLASSNAMES,\n        appendGroupInSearch: false,\n    };\n\n    var removeItem = function (item) {\n        var itemEl = item.itemEl;\n        if (itemEl) {\n            itemEl.remove();\n            item.itemEl = undefined;\n        }\n    };\n    function items(s, action, context) {\n        var state = s;\n        var update = true;\n        switch (action.type) {\n            case ActionType.ADD_ITEM: {\n                action.item.selected = true;\n                var el = action.item.element;\n                if (el) {\n                    el.selected = true;\n                    el.setAttribute('selected', '');\n                }\n                state.push(action.item);\n                break;\n            }\n            case ActionType.REMOVE_ITEM: {\n                action.item.selected = false;\n                var el = action.item.element;\n                if (el) {\n                    el.selected = false;\n                    el.removeAttribute('selected');\n                    // For a select-one, if all options are deselected, the first item is selected. To set a black value, select.value needs to be set\n                    var select = el.parentElement;\n                    if (select && isHtmlSelectElement(select) && select.type === PassedElementTypes.SelectOne) {\n                        select.value = '';\n                    }\n                }\n                // this is mixing concerns, but this is *so much faster*\n                removeItem(action.item);\n                state = state.filter(function (choice) { return choice.id !== action.item.id; });\n                break;\n            }\n            case ActionType.REMOVE_CHOICE: {\n                removeItem(action.choice);\n                state = state.filter(function (item) { return item.id !== action.choice.id; });\n                break;\n            }\n            case ActionType.HIGHLIGHT_ITEM: {\n                var highlighted = action.highlighted;\n                var item = state.find(function (obj) { return obj.id === action.item.id; });\n                if (item && item.highlighted !== highlighted) {\n                    item.highlighted = highlighted;\n                    if (context) {\n                        updateClassList(item, highlighted ? context.classNames.highlightedState : context.classNames.selectedState, highlighted ? context.classNames.selectedState : context.classNames.highlightedState);\n                    }\n                }\n                break;\n            }\n            default: {\n                update = false;\n                break;\n            }\n        }\n        return { state: state, update: update };\n    }\n\n    function groups(s, action) {\n        var state = s;\n        var update = true;\n        switch (action.type) {\n            case ActionType.ADD_GROUP: {\n                state.push(action.group);\n                break;\n            }\n            case ActionType.CLEAR_CHOICES: {\n                state = [];\n                break;\n            }\n            default: {\n                update = false;\n                break;\n            }\n        }\n        return { state: state, update: update };\n    }\n\n    /* eslint-disable */\n    function choices(s, action, context) {\n        var state = s;\n        var update = true;\n        switch (action.type) {\n            case ActionType.ADD_CHOICE: {\n                state.push(action.choice);\n                break;\n            }\n            case ActionType.REMOVE_CHOICE: {\n                action.choice.choiceEl = undefined;\n                if (action.choice.group) {\n                    action.choice.group.choices = action.choice.group.choices.filter(function (obj) { return obj.id !== action.choice.id; });\n                }\n                state = state.filter(function (obj) { return obj.id !== action.choice.id; });\n                break;\n            }\n            case ActionType.ADD_ITEM:\n            case ActionType.REMOVE_ITEM: {\n                action.item.choiceEl = undefined;\n                break;\n            }\n            case ActionType.FILTER_CHOICES: {\n                // avoid O(n^2) algorithm complexity when searching/filtering choices\n                var scoreLookup_1 = [];\n                action.results.forEach(function (result) {\n                    scoreLookup_1[result.item.id] = result;\n                });\n                state.forEach(function (choice) {\n                    var result = scoreLookup_1[choice.id];\n                    if (result !== undefined) {\n                        choice.score = result.score;\n                        choice.rank = result.rank;\n                        choice.active = true;\n                    }\n                    else {\n                        choice.score = 0;\n                        choice.rank = 0;\n                        choice.active = false;\n                    }\n                    if (context && context.appendGroupInSearch) {\n                        choice.choiceEl = undefined;\n                    }\n                });\n                break;\n            }\n            case ActionType.ACTIVATE_CHOICES: {\n                state.forEach(function (choice) {\n                    choice.active = action.active;\n                    if (context && context.appendGroupInSearch) {\n                        choice.choiceEl = undefined;\n                    }\n                });\n                break;\n            }\n            case ActionType.CLEAR_CHOICES: {\n                state = [];\n                break;\n            }\n            default: {\n                update = false;\n                break;\n            }\n        }\n        return { state: state, update: update };\n    }\n\n    var reducers = {\n        groups: groups,\n        items: items,\n        choices: choices,\n    };\n    var Store = /** @class */ (function () {\n        function Store(context) {\n            this._state = this.defaultState;\n            this._listeners = [];\n            this._txn = 0;\n            this._context = context;\n        }\n        Object.defineProperty(Store.prototype, \"defaultState\", {\n            // eslint-disable-next-line class-methods-use-this\n            get: function () {\n                return {\n                    groups: [],\n                    items: [],\n                    choices: [],\n                };\n            },\n            enumerable: false,\n            configurable: true\n        });\n        // eslint-disable-next-line class-methods-use-this\n        Store.prototype.changeSet = function (init) {\n            return {\n                groups: init,\n                items: init,\n                choices: init,\n            };\n        };\n        Store.prototype.reset = function () {\n            this._state = this.defaultState;\n            var changes = this.changeSet(true);\n            if (this._txn) {\n                this._changeSet = changes;\n            }\n            else {\n                this._listeners.forEach(function (l) { return l(changes); });\n            }\n        };\n        Store.prototype.subscribe = function (onChange) {\n            this._listeners.push(onChange);\n            return this;\n        };\n        Store.prototype.dispatch = function (action) {\n            var _this = this;\n            var state = this._state;\n            var hasChanges = false;\n            var changes = this._changeSet || this.changeSet(false);\n            Object.keys(reducers).forEach(function (key) {\n                var stateUpdate = reducers[key](state[key], action, _this._context);\n                if (stateUpdate.update) {\n                    hasChanges = true;\n                    changes[key] = true;\n                    state[key] = stateUpdate.state;\n                }\n            });\n            if (hasChanges) {\n                if (this._txn) {\n                    this._changeSet = changes;\n                }\n                else {\n                    this._listeners.forEach(function (l) { return l(changes); });\n                }\n            }\n        };\n        Store.prototype.withTxn = function (func) {\n            this._txn++;\n            try {\n                func();\n            }\n            finally {\n                this._txn = Math.max(0, this._txn - 1);\n                if (!this._txn) {\n                    var changeSet_1 = this._changeSet;\n                    if (changeSet_1) {\n                        this._changeSet = undefined;\n                        this._listeners.forEach(function (l) { return l(changeSet_1); });\n                    }\n                }\n            }\n        };\n        Object.defineProperty(Store.prototype, \"state\", {\n            /**\n             * Get store object\n             */\n            get: function () {\n                return this._state;\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(Store.prototype, \"items\", {\n            /**\n             * Get items from store\n             */\n            get: function () {\n                return this.state.items;\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(Store.prototype, \"highlightedActiveItems\", {\n            /**\n             * Get highlighted items from store\n             */\n            get: function () {\n                return this.items.filter(function (item) { return item.active && item.highlighted; });\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(Store.prototype, \"choices\", {\n            /**\n             * Get choices from store\n             */\n            get: function () {\n                return this.state.choices;\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(Store.prototype, \"activeChoices\", {\n            /**\n             * Get active choices from store\n             */\n            get: function () {\n                return this.choices.filter(function (choice) { return choice.active; });\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(Store.prototype, \"searchableChoices\", {\n            /**\n             * Get choices that can be searched (excluding placeholders or disabled choices)\n             */\n            get: function () {\n                var context = this._context;\n                return this.choices.filter(function (choice) { return !choice.placeholder && (context.searchDisabledChoices || !choice.disabled); });\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(Store.prototype, \"groups\", {\n            /**\n             * Get groups from store\n             */\n            get: function () {\n                return this.state.groups;\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(Store.prototype, \"activeGroups\", {\n            /**\n             * Get active groups from store\n             */\n            get: function () {\n                var _this = this;\n                return this.state.groups.filter(function (group) {\n                    var isActive = group.active && !group.disabled;\n                    var hasActiveOptions = _this.state.choices.some(function (choice) { return choice.active && !choice.disabled; });\n                    return isActive && hasActiveOptions;\n                }, []);\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Store.prototype.inTxn = function () {\n            return this._txn > 0;\n        };\n        /**\n         * Get single choice by it's ID\n         */\n        Store.prototype.getChoiceById = function (id) {\n            return this.activeChoices.find(function (choice) { return choice.id === id; });\n        };\n        /**\n         * Get group by group id\n         */\n        Store.prototype.getGroupById = function (id) {\n            return this.groups.find(function (group) { return group.id === id; });\n        };\n        return Store;\n    }());\n\n    var NoticeTypes = {\n        noChoices: 'no-choices',\n        noResults: 'no-results',\n        addChoice: 'add-choice',\n        generic: '',\n    };\n\n    function _defineProperty(e, r, t) {\n      return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {\n        value: t,\n        enumerable: true,\n        configurable: true,\n        writable: true\n      }) : e[r] = t, e;\n    }\n    function ownKeys(e, r) {\n      var t = Object.keys(e);\n      if (Object.getOwnPropertySymbols) {\n        var o = Object.getOwnPropertySymbols(e);\n        r && (o = o.filter(function (r) {\n          return Object.getOwnPropertyDescriptor(e, r).enumerable;\n        })), t.push.apply(t, o);\n      }\n      return t;\n    }\n    function _objectSpread2(e) {\n      for (var r = 1; r < arguments.length; r++) {\n        var t = null != arguments[r] ? arguments[r] : {};\n        r % 2 ? ownKeys(Object(t), true).forEach(function (r) {\n          _defineProperty(e, r, t[r]);\n        }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {\n          Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));\n        });\n      }\n      return e;\n    }\n    function _toPrimitive(t, r) {\n      if (\"object\" != typeof t || !t) return t;\n      var e = t[Symbol.toPrimitive];\n      if (void 0 !== e) {\n        var i = e.call(t, r);\n        if (\"object\" != typeof i) return i;\n        throw new TypeError(\"@@toPrimitive must return a primitive value.\");\n      }\n      return (\"string\" === r ? String : Number)(t);\n    }\n    function _toPropertyKey(t) {\n      var i = _toPrimitive(t, \"string\");\n      return \"symbol\" == typeof i ? i : i + \"\";\n    }\n\n    /**\n     * Fuse.js v7.0.0 - Lightweight fuzzy-search (http://fusejs.io)\n     *\n     * Copyright (c) 2023 Kiro Risk (http://kiro.me)\n     * All Rights Reserved. Apache Software License 2.0\n     *\n     * http://www.apache.org/licenses/LICENSE-2.0\n     */\n\n    function isArray(value) {\n      return !Array.isArray ? getTag(value) === '[object Array]' : Array.isArray(value);\n    }\n    function baseToString(value) {\n      // Exit early for strings to avoid a performance hit in some environments.\n      if (typeof value == 'string') {\n        return value;\n      }\n      let result = value + '';\n      return result == '0' && 1 / value == -Infinity ? '-0' : result;\n    }\n    function toString(value) {\n      return value == null ? '' : baseToString(value);\n    }\n    function isString(value) {\n      return typeof value === 'string';\n    }\n    function isNumber(value) {\n      return typeof value === 'number';\n    }\n\n    // Adapted from: https://github.com/lodash/lodash/blob/master/isBoolean.js\n    function isBoolean(value) {\n      return value === true || value === false || isObjectLike(value) && getTag(value) == '[object Boolean]';\n    }\n    function isObject(value) {\n      return typeof value === 'object';\n    }\n\n    // Checks if `value` is object-like.\n    function isObjectLike(value) {\n      return isObject(value) && value !== null;\n    }\n    function isDefined(value) {\n      return value !== undefined && value !== null;\n    }\n    function isBlank(value) {\n      return !value.trim().length;\n    }\n\n    // Gets the `toStringTag` of `value`.\n    // Adapted from: https://github.com/lodash/lodash/blob/master/.internal/getTag.js\n    function getTag(value) {\n      return value == null ? value === undefined ? '[object Undefined]' : '[object Null]' : Object.prototype.toString.call(value);\n    }\n    const INCORRECT_INDEX_TYPE = \"Incorrect 'index' type\";\n    const LOGICAL_SEARCH_INVALID_QUERY_FOR_KEY = key => `Invalid value for key ${key}`;\n    const PATTERN_LENGTH_TOO_LARGE = max => `Pattern length exceeds max of ${max}.`;\n    const MISSING_KEY_PROPERTY = name => `Missing ${name} property in key`;\n    const INVALID_KEY_WEIGHT_VALUE = key => `Property 'weight' in key '${key}' must be a positive integer`;\n    const hasOwn = Object.prototype.hasOwnProperty;\n    class KeyStore {\n      constructor(keys) {\n        this._keys = [];\n        this._keyMap = {};\n        let totalWeight = 0;\n        keys.forEach(key => {\n          let obj = createKey(key);\n          this._keys.push(obj);\n          this._keyMap[obj.id] = obj;\n          totalWeight += obj.weight;\n        });\n\n        // Normalize weights so that their sum is equal to 1\n        this._keys.forEach(key => {\n          key.weight /= totalWeight;\n        });\n      }\n      get(keyId) {\n        return this._keyMap[keyId];\n      }\n      keys() {\n        return this._keys;\n      }\n      toJSON() {\n        return JSON.stringify(this._keys);\n      }\n    }\n    function createKey(key) {\n      let path = null;\n      let id = null;\n      let src = null;\n      let weight = 1;\n      let getFn = null;\n      if (isString(key) || isArray(key)) {\n        src = key;\n        path = createKeyPath(key);\n        id = createKeyId(key);\n      } else {\n        if (!hasOwn.call(key, 'name')) {\n          throw new Error(MISSING_KEY_PROPERTY('name'));\n        }\n        const name = key.name;\n        src = name;\n        if (hasOwn.call(key, 'weight')) {\n          weight = key.weight;\n          if (weight <= 0) {\n            throw new Error(INVALID_KEY_WEIGHT_VALUE(name));\n          }\n        }\n        path = createKeyPath(name);\n        id = createKeyId(name);\n        getFn = key.getFn;\n      }\n      return {\n        path,\n        id,\n        weight,\n        src,\n        getFn\n      };\n    }\n    function createKeyPath(key) {\n      return isArray(key) ? key : key.split('.');\n    }\n    function createKeyId(key) {\n      return isArray(key) ? key.join('.') : key;\n    }\n    function get(obj, path) {\n      let list = [];\n      let arr = false;\n      const deepGet = (obj, path, index) => {\n        if (!isDefined(obj)) {\n          return;\n        }\n        if (!path[index]) {\n          // If there's no path left, we've arrived at the object we care about.\n          list.push(obj);\n        } else {\n          let key = path[index];\n          const value = obj[key];\n          if (!isDefined(value)) {\n            return;\n          }\n\n          // If we're at the last value in the path, and if it's a string/number/bool,\n          // add it to the list\n          if (index === path.length - 1 && (isString(value) || isNumber(value) || isBoolean(value))) {\n            list.push(toString(value));\n          } else if (isArray(value)) {\n            arr = true;\n            // Search each item in the array.\n            for (let i = 0, len = value.length; i < len; i += 1) {\n              deepGet(value[i], path, index + 1);\n            }\n          } else if (path.length) {\n            // An object. Recurse further.\n            deepGet(value, path, index + 1);\n          }\n        }\n      };\n\n      // Backwards compatibility (since path used to be a string)\n      deepGet(obj, isString(path) ? path.split('.') : path, 0);\n      return arr ? list : list[0];\n    }\n    const MatchOptions = {\n      // Whether the matches should be included in the result set. When `true`, each record in the result\n      // set will include the indices of the matched characters.\n      // These can consequently be used for highlighting purposes.\n      includeMatches: false,\n      // When `true`, the matching function will continue to the end of a search pattern even if\n      // a perfect match has already been located in the string.\n      findAllMatches: false,\n      // Minimum number of characters that must be matched before a result is considered a match\n      minMatchCharLength: 1\n    };\n    const BasicOptions = {\n      // When `true`, the algorithm continues searching to the end of the input even if a perfect\n      // match is found before the end of the same input.\n      isCaseSensitive: false,\n      // When true, the matching function will continue to the end of a search pattern even if\n      includeScore: false,\n      // List of properties that will be searched. This also supports nested properties.\n      keys: [],\n      // Whether to sort the result list, by score\n      shouldSort: true,\n      // Default sort function: sort by ascending score, ascending index\n      sortFn: (a, b) => a.score === b.score ? a.idx < b.idx ? -1 : 1 : a.score < b.score ? -1 : 1\n    };\n    const FuzzyOptions = {\n      // Approximately where in the text is the pattern expected to be found?\n      location: 0,\n      // At what point does the match algorithm give up. A threshold of '0.0' requires a perfect match\n      // (of both letters and location), a threshold of '1.0' would match anything.\n      threshold: 0.6,\n      // Determines how close the match must be to the fuzzy location (specified above).\n      // An exact letter match which is 'distance' characters away from the fuzzy location\n      // would score as a complete mismatch. A distance of '0' requires the match be at\n      // the exact location specified, a threshold of '1000' would require a perfect match\n      // to be within 800 characters of the fuzzy location to be found using a 0.8 threshold.\n      distance: 100\n    };\n    const AdvancedOptions = {\n      // When `true`, it enables the use of unix-like search commands\n      useExtendedSearch: false,\n      // The get function to use when fetching an object's properties.\n      // The default will search nested paths *ie foo.bar.baz*\n      getFn: get,\n      // When `true`, search will ignore `location` and `distance`, so it won't matter\n      // where in the string the pattern appears.\n      // More info: https://fusejs.io/concepts/scoring-theory.html#fuzziness-score\n      ignoreLocation: false,\n      // When `true`, the calculation for the relevance score (used for sorting) will\n      // ignore the field-length norm.\n      // More info: https://fusejs.io/concepts/scoring-theory.html#field-length-norm\n      ignoreFieldNorm: false,\n      // The weight to determine how much field length norm effects scoring.\n      fieldNormWeight: 1\n    };\n    var Config = _objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({}, BasicOptions), MatchOptions), FuzzyOptions), AdvancedOptions);\n    const SPACE = /[^ ]+/g;\n\n    // Field-length norm: the shorter the field, the higher the weight.\n    // Set to 3 decimals to reduce index size.\n    function norm(weight = 1, mantissa = 3) {\n      const cache = new Map();\n      const m = Math.pow(10, mantissa);\n      return {\n        get(value) {\n          const numTokens = value.match(SPACE).length;\n          if (cache.has(numTokens)) {\n            return cache.get(numTokens);\n          }\n\n          // Default function is 1/sqrt(x), weight makes that variable\n          const norm = 1 / Math.pow(numTokens, 0.5 * weight);\n\n          // In place of `toFixed(mantissa)`, for faster computation\n          const n = parseFloat(Math.round(norm * m) / m);\n          cache.set(numTokens, n);\n          return n;\n        },\n        clear() {\n          cache.clear();\n        }\n      };\n    }\n    class FuseIndex {\n      constructor({\n        getFn = Config.getFn,\n        fieldNormWeight = Config.fieldNormWeight\n      } = {}) {\n        this.norm = norm(fieldNormWeight, 3);\n        this.getFn = getFn;\n        this.isCreated = false;\n        this.setIndexRecords();\n      }\n      setSources(docs = []) {\n        this.docs = docs;\n      }\n      setIndexRecords(records = []) {\n        this.records = records;\n      }\n      setKeys(keys = []) {\n        this.keys = keys;\n        this._keysMap = {};\n        keys.forEach((key, idx) => {\n          this._keysMap[key.id] = idx;\n        });\n      }\n      create() {\n        if (this.isCreated || !this.docs.length) {\n          return;\n        }\n        this.isCreated = true;\n\n        // List is Array<String>\n        if (isString(this.docs[0])) {\n          this.docs.forEach((doc, docIndex) => {\n            this._addString(doc, docIndex);\n          });\n        } else {\n          // List is Array<Object>\n          this.docs.forEach((doc, docIndex) => {\n            this._addObject(doc, docIndex);\n          });\n        }\n        this.norm.clear();\n      }\n      // Adds a doc to the end of the index\n      add(doc) {\n        const idx = this.size();\n        if (isString(doc)) {\n          this._addString(doc, idx);\n        } else {\n          this._addObject(doc, idx);\n        }\n      }\n      // Removes the doc at the specified index of the index\n      removeAt(idx) {\n        this.records.splice(idx, 1);\n\n        // Change ref index of every subsquent doc\n        for (let i = idx, len = this.size(); i < len; i += 1) {\n          this.records[i].i -= 1;\n        }\n      }\n      getValueForItemAtKeyId(item, keyId) {\n        return item[this._keysMap[keyId]];\n      }\n      size() {\n        return this.records.length;\n      }\n      _addString(doc, docIndex) {\n        if (!isDefined(doc) || isBlank(doc)) {\n          return;\n        }\n        let record = {\n          v: doc,\n          i: docIndex,\n          n: this.norm.get(doc)\n        };\n        this.records.push(record);\n      }\n      _addObject(doc, docIndex) {\n        let record = {\n          i: docIndex,\n          $: {}\n        };\n\n        // Iterate over every key (i.e, path), and fetch the value at that key\n        this.keys.forEach((key, keyIndex) => {\n          let value = key.getFn ? key.getFn(doc) : this.getFn(doc, key.path);\n          if (!isDefined(value)) {\n            return;\n          }\n          if (isArray(value)) {\n            let subRecords = [];\n            const stack = [{\n              nestedArrIndex: -1,\n              value\n            }];\n            while (stack.length) {\n              const {\n                nestedArrIndex,\n                value\n              } = stack.pop();\n              if (!isDefined(value)) {\n                continue;\n              }\n              if (isString(value) && !isBlank(value)) {\n                let subRecord = {\n                  v: value,\n                  i: nestedArrIndex,\n                  n: this.norm.get(value)\n                };\n                subRecords.push(subRecord);\n              } else if (isArray(value)) {\n                value.forEach((item, k) => {\n                  stack.push({\n                    nestedArrIndex: k,\n                    value: item\n                  });\n                });\n              } else ;\n            }\n            record.$[keyIndex] = subRecords;\n          } else if (isString(value) && !isBlank(value)) {\n            let subRecord = {\n              v: value,\n              n: this.norm.get(value)\n            };\n            record.$[keyIndex] = subRecord;\n          }\n        });\n        this.records.push(record);\n      }\n      toJSON() {\n        return {\n          keys: this.keys,\n          records: this.records\n        };\n      }\n    }\n    function createIndex(keys, docs, {\n      getFn = Config.getFn,\n      fieldNormWeight = Config.fieldNormWeight\n    } = {}) {\n      const myIndex = new FuseIndex({\n        getFn,\n        fieldNormWeight\n      });\n      myIndex.setKeys(keys.map(createKey));\n      myIndex.setSources(docs);\n      myIndex.create();\n      return myIndex;\n    }\n    function parseIndex(data, {\n      getFn = Config.getFn,\n      fieldNormWeight = Config.fieldNormWeight\n    } = {}) {\n      const {\n        keys,\n        records\n      } = data;\n      const myIndex = new FuseIndex({\n        getFn,\n        fieldNormWeight\n      });\n      myIndex.setKeys(keys);\n      myIndex.setIndexRecords(records);\n      return myIndex;\n    }\n    function computeScore$1(pattern, {\n      errors = 0,\n      currentLocation = 0,\n      expectedLocation = 0,\n      distance = Config.distance,\n      ignoreLocation = Config.ignoreLocation\n    } = {}) {\n      const accuracy = errors / pattern.length;\n      if (ignoreLocation) {\n        return accuracy;\n      }\n      const proximity = Math.abs(expectedLocation - currentLocation);\n      if (!distance) {\n        // Dodge divide by zero error.\n        return proximity ? 1.0 : accuracy;\n      }\n      return accuracy + proximity / distance;\n    }\n    function convertMaskToIndices(matchmask = [], minMatchCharLength = Config.minMatchCharLength) {\n      let indices = [];\n      let start = -1;\n      let end = -1;\n      let i = 0;\n      for (let len = matchmask.length; i < len; i += 1) {\n        let match = matchmask[i];\n        if (match && start === -1) {\n          start = i;\n        } else if (!match && start !== -1) {\n          end = i - 1;\n          if (end - start + 1 >= minMatchCharLength) {\n            indices.push([start, end]);\n          }\n          start = -1;\n        }\n      }\n\n      // (i-1 - start) + 1 => i - start\n      if (matchmask[i - 1] && i - start >= minMatchCharLength) {\n        indices.push([start, i - 1]);\n      }\n      return indices;\n    }\n\n    // Machine word size\n    const MAX_BITS = 32;\n    function search(text, pattern, patternAlphabet, {\n      location = Config.location,\n      distance = Config.distance,\n      threshold = Config.threshold,\n      findAllMatches = Config.findAllMatches,\n      minMatchCharLength = Config.minMatchCharLength,\n      includeMatches = Config.includeMatches,\n      ignoreLocation = Config.ignoreLocation\n    } = {}) {\n      if (pattern.length > MAX_BITS) {\n        throw new Error(PATTERN_LENGTH_TOO_LARGE(MAX_BITS));\n      }\n      const patternLen = pattern.length;\n      // Set starting location at beginning text and initialize the alphabet.\n      const textLen = text.length;\n      // Handle the case when location > text.length\n      const expectedLocation = Math.max(0, Math.min(location, textLen));\n      // Highest score beyond which we give up.\n      let currentThreshold = threshold;\n      // Is there a nearby exact match? (speedup)\n      let bestLocation = expectedLocation;\n\n      // Performance: only computer matches when the minMatchCharLength > 1\n      // OR if `includeMatches` is true.\n      const computeMatches = minMatchCharLength > 1 || includeMatches;\n      // A mask of the matches, used for building the indices\n      const matchMask = computeMatches ? Array(textLen) : [];\n      let index;\n\n      // Get all exact matches, here for speed up\n      while ((index = text.indexOf(pattern, bestLocation)) > -1) {\n        let score = computeScore$1(pattern, {\n          currentLocation: index,\n          expectedLocation,\n          distance,\n          ignoreLocation\n        });\n        currentThreshold = Math.min(score, currentThreshold);\n        bestLocation = index + patternLen;\n        if (computeMatches) {\n          let i = 0;\n          while (i < patternLen) {\n            matchMask[index + i] = 1;\n            i += 1;\n          }\n        }\n      }\n\n      // Reset the best location\n      bestLocation = -1;\n      let lastBitArr = [];\n      let finalScore = 1;\n      let binMax = patternLen + textLen;\n      const mask = 1 << patternLen - 1;\n      for (let i = 0; i < patternLen; i += 1) {\n        // Scan for the best match; each iteration allows for one more error.\n        // Run a binary search to determine how far from the match location we can stray\n        // at this error level.\n        let binMin = 0;\n        let binMid = binMax;\n        while (binMin < binMid) {\n          const score = computeScore$1(pattern, {\n            errors: i,\n            currentLocation: expectedLocation + binMid,\n            expectedLocation,\n            distance,\n            ignoreLocation\n          });\n          if (score <= currentThreshold) {\n            binMin = binMid;\n          } else {\n            binMax = binMid;\n          }\n          binMid = Math.floor((binMax - binMin) / 2 + binMin);\n        }\n\n        // Use the result from this iteration as the maximum for the next.\n        binMax = binMid;\n        let start = Math.max(1, expectedLocation - binMid + 1);\n        let finish = findAllMatches ? textLen : Math.min(expectedLocation + binMid, textLen) + patternLen;\n\n        // Initialize the bit array\n        let bitArr = Array(finish + 2);\n        bitArr[finish + 1] = (1 << i) - 1;\n        for (let j = finish; j >= start; j -= 1) {\n          let currentLocation = j - 1;\n          let charMatch = patternAlphabet[text.charAt(currentLocation)];\n          if (computeMatches) {\n            // Speed up: quick bool to int conversion (i.e, `charMatch ? 1 : 0`)\n            matchMask[currentLocation] = +!!charMatch;\n          }\n\n          // First pass: exact match\n          bitArr[j] = (bitArr[j + 1] << 1 | 1) & charMatch;\n\n          // Subsequent passes: fuzzy match\n          if (i) {\n            bitArr[j] |= (lastBitArr[j + 1] | lastBitArr[j]) << 1 | 1 | lastBitArr[j + 1];\n          }\n          if (bitArr[j] & mask) {\n            finalScore = computeScore$1(pattern, {\n              errors: i,\n              currentLocation,\n              expectedLocation,\n              distance,\n              ignoreLocation\n            });\n\n            // This match will almost certainly be better than any existing match.\n            // But check anyway.\n            if (finalScore <= currentThreshold) {\n              // Indeed it is\n              currentThreshold = finalScore;\n              bestLocation = currentLocation;\n\n              // Already passed `loc`, downhill from here on in.\n              if (bestLocation <= expectedLocation) {\n                break;\n              }\n\n              // When passing `bestLocation`, don't exceed our current distance from `expectedLocation`.\n              start = Math.max(1, 2 * expectedLocation - bestLocation);\n            }\n          }\n        }\n\n        // No hope for a (better) match at greater error levels.\n        const score = computeScore$1(pattern, {\n          errors: i + 1,\n          currentLocation: expectedLocation,\n          expectedLocation,\n          distance,\n          ignoreLocation\n        });\n        if (score > currentThreshold) {\n          break;\n        }\n        lastBitArr = bitArr;\n      }\n      const result = {\n        isMatch: bestLocation >= 0,\n        // Count exact matches (those with a score of 0) to be \"almost\" exact\n        score: Math.max(0.001, finalScore)\n      };\n      if (computeMatches) {\n        const indices = convertMaskToIndices(matchMask, minMatchCharLength);\n        if (!indices.length) {\n          result.isMatch = false;\n        } else if (includeMatches) {\n          result.indices = indices;\n        }\n      }\n      return result;\n    }\n    function createPatternAlphabet(pattern) {\n      let mask = {};\n      for (let i = 0, len = pattern.length; i < len; i += 1) {\n        const char = pattern.charAt(i);\n        mask[char] = (mask[char] || 0) | 1 << len - i - 1;\n      }\n      return mask;\n    }\n    class BitapSearch {\n      constructor(pattern, {\n        location = Config.location,\n        threshold = Config.threshold,\n        distance = Config.distance,\n        includeMatches = Config.includeMatches,\n        findAllMatches = Config.findAllMatches,\n        minMatchCharLength = Config.minMatchCharLength,\n        isCaseSensitive = Config.isCaseSensitive,\n        ignoreLocation = Config.ignoreLocation\n      } = {}) {\n        this.options = {\n          location,\n          threshold,\n          distance,\n          includeMatches,\n          findAllMatches,\n          minMatchCharLength,\n          isCaseSensitive,\n          ignoreLocation\n        };\n        this.pattern = isCaseSensitive ? pattern : pattern.toLowerCase();\n        this.chunks = [];\n        if (!this.pattern.length) {\n          return;\n        }\n        const addChunk = (pattern, startIndex) => {\n          this.chunks.push({\n            pattern,\n            alphabet: createPatternAlphabet(pattern),\n            startIndex\n          });\n        };\n        const len = this.pattern.length;\n        if (len > MAX_BITS) {\n          let i = 0;\n          const remainder = len % MAX_BITS;\n          const end = len - remainder;\n          while (i < end) {\n            addChunk(this.pattern.substr(i, MAX_BITS), i);\n            i += MAX_BITS;\n          }\n          if (remainder) {\n            const startIndex = len - MAX_BITS;\n            addChunk(this.pattern.substr(startIndex), startIndex);\n          }\n        } else {\n          addChunk(this.pattern, 0);\n        }\n      }\n      searchIn(text) {\n        const {\n          isCaseSensitive,\n          includeMatches\n        } = this.options;\n        if (!isCaseSensitive) {\n          text = text.toLowerCase();\n        }\n\n        // Exact match\n        if (this.pattern === text) {\n          let result = {\n            isMatch: true,\n            score: 0\n          };\n          if (includeMatches) {\n            result.indices = [[0, text.length - 1]];\n          }\n          return result;\n        }\n\n        // Otherwise, use Bitap algorithm\n        const {\n          location,\n          distance,\n          threshold,\n          findAllMatches,\n          minMatchCharLength,\n          ignoreLocation\n        } = this.options;\n        let allIndices = [];\n        let totalScore = 0;\n        let hasMatches = false;\n        this.chunks.forEach(({\n          pattern,\n          alphabet,\n          startIndex\n        }) => {\n          const {\n            isMatch,\n            score,\n            indices\n          } = search(text, pattern, alphabet, {\n            location: location + startIndex,\n            distance,\n            threshold,\n            findAllMatches,\n            minMatchCharLength,\n            includeMatches,\n            ignoreLocation\n          });\n          if (isMatch) {\n            hasMatches = true;\n          }\n          totalScore += score;\n          if (isMatch && indices) {\n            allIndices = [...allIndices, ...indices];\n          }\n        });\n        let result = {\n          isMatch: hasMatches,\n          score: hasMatches ? totalScore / this.chunks.length : 1\n        };\n        if (hasMatches && includeMatches) {\n          result.indices = allIndices;\n        }\n        return result;\n      }\n    }\n    class BaseMatch {\n      constructor(pattern) {\n        this.pattern = pattern;\n      }\n      static isMultiMatch(pattern) {\n        return getMatch(pattern, this.multiRegex);\n      }\n      static isSingleMatch(pattern) {\n        return getMatch(pattern, this.singleRegex);\n      }\n      search( /*text*/) {}\n    }\n    function getMatch(pattern, exp) {\n      const matches = pattern.match(exp);\n      return matches ? matches[1] : null;\n    }\n\n    // Token: 'file\n\n    class ExactMatch extends BaseMatch {\n      constructor(pattern) {\n        super(pattern);\n      }\n      static get type() {\n        return 'exact';\n      }\n      static get multiRegex() {\n        return /^=\"(.*)\"$/;\n      }\n      static get singleRegex() {\n        return /^=(.*)$/;\n      }\n      search(text) {\n        const isMatch = text === this.pattern;\n        return {\n          isMatch,\n          score: isMatch ? 0 : 1,\n          indices: [0, this.pattern.length - 1]\n        };\n      }\n    }\n\n    // Token: !fire\n\n    class InverseExactMatch extends BaseMatch {\n      constructor(pattern) {\n        super(pattern);\n      }\n      static get type() {\n        return 'inverse-exact';\n      }\n      static get multiRegex() {\n        return /^!\"(.*)\"$/;\n      }\n      static get singleRegex() {\n        return /^!(.*)$/;\n      }\n      search(text) {\n        const index = text.indexOf(this.pattern);\n        const isMatch = index === -1;\n        return {\n          isMatch,\n          score: isMatch ? 0 : 1,\n          indices: [0, text.length - 1]\n        };\n      }\n    }\n\n    // Token: ^file\n\n    class PrefixExactMatch extends BaseMatch {\n      constructor(pattern) {\n        super(pattern);\n      }\n      static get type() {\n        return 'prefix-exact';\n      }\n      static get multiRegex() {\n        return /^\\^\"(.*)\"$/;\n      }\n      static get singleRegex() {\n        return /^\\^(.*)$/;\n      }\n      search(text) {\n        const isMatch = text.startsWith(this.pattern);\n        return {\n          isMatch,\n          score: isMatch ? 0 : 1,\n          indices: [0, this.pattern.length - 1]\n        };\n      }\n    }\n\n    // Token: !^fire\n\n    class InversePrefixExactMatch extends BaseMatch {\n      constructor(pattern) {\n        super(pattern);\n      }\n      static get type() {\n        return 'inverse-prefix-exact';\n      }\n      static get multiRegex() {\n        return /^!\\^\"(.*)\"$/;\n      }\n      static get singleRegex() {\n        return /^!\\^(.*)$/;\n      }\n      search(text) {\n        const isMatch = !text.startsWith(this.pattern);\n        return {\n          isMatch,\n          score: isMatch ? 0 : 1,\n          indices: [0, text.length - 1]\n        };\n      }\n    }\n\n    // Token: .file$\n\n    class SuffixExactMatch extends BaseMatch {\n      constructor(pattern) {\n        super(pattern);\n      }\n      static get type() {\n        return 'suffix-exact';\n      }\n      static get multiRegex() {\n        return /^\"(.*)\"\\$$/;\n      }\n      static get singleRegex() {\n        return /^(.*)\\$$/;\n      }\n      search(text) {\n        const isMatch = text.endsWith(this.pattern);\n        return {\n          isMatch,\n          score: isMatch ? 0 : 1,\n          indices: [text.length - this.pattern.length, text.length - 1]\n        };\n      }\n    }\n\n    // Token: !.file$\n\n    class InverseSuffixExactMatch extends BaseMatch {\n      constructor(pattern) {\n        super(pattern);\n      }\n      static get type() {\n        return 'inverse-suffix-exact';\n      }\n      static get multiRegex() {\n        return /^!\"(.*)\"\\$$/;\n      }\n      static get singleRegex() {\n        return /^!(.*)\\$$/;\n      }\n      search(text) {\n        const isMatch = !text.endsWith(this.pattern);\n        return {\n          isMatch,\n          score: isMatch ? 0 : 1,\n          indices: [0, text.length - 1]\n        };\n      }\n    }\n    class FuzzyMatch extends BaseMatch {\n      constructor(pattern, {\n        location = Config.location,\n        threshold = Config.threshold,\n        distance = Config.distance,\n        includeMatches = Config.includeMatches,\n        findAllMatches = Config.findAllMatches,\n        minMatchCharLength = Config.minMatchCharLength,\n        isCaseSensitive = Config.isCaseSensitive,\n        ignoreLocation = Config.ignoreLocation\n      } = {}) {\n        super(pattern);\n        this._bitapSearch = new BitapSearch(pattern, {\n          location,\n          threshold,\n          distance,\n          includeMatches,\n          findAllMatches,\n          minMatchCharLength,\n          isCaseSensitive,\n          ignoreLocation\n        });\n      }\n      static get type() {\n        return 'fuzzy';\n      }\n      static get multiRegex() {\n        return /^\"(.*)\"$/;\n      }\n      static get singleRegex() {\n        return /^(.*)$/;\n      }\n      search(text) {\n        return this._bitapSearch.searchIn(text);\n      }\n    }\n\n    // Token: 'file\n\n    class IncludeMatch extends BaseMatch {\n      constructor(pattern) {\n        super(pattern);\n      }\n      static get type() {\n        return 'include';\n      }\n      static get multiRegex() {\n        return /^'\"(.*)\"$/;\n      }\n      static get singleRegex() {\n        return /^'(.*)$/;\n      }\n      search(text) {\n        let location = 0;\n        let index;\n        const indices = [];\n        const patternLen = this.pattern.length;\n\n        // Get all exact matches\n        while ((index = text.indexOf(this.pattern, location)) > -1) {\n          location = index + patternLen;\n          indices.push([index, location - 1]);\n        }\n        const isMatch = !!indices.length;\n        return {\n          isMatch,\n          score: isMatch ? 0 : 1,\n          indices\n        };\n      }\n    }\n\n    // ❗Order is important. DO NOT CHANGE.\n    const searchers = [ExactMatch, IncludeMatch, PrefixExactMatch, InversePrefixExactMatch, InverseSuffixExactMatch, SuffixExactMatch, InverseExactMatch, FuzzyMatch];\n    const searchersLen = searchers.length;\n\n    // Regex to split by spaces, but keep anything in quotes together\n    const SPACE_RE = / +(?=(?:[^\\\"]*\\\"[^\\\"]*\\\")*[^\\\"]*$)/;\n    const OR_TOKEN = '|';\n\n    // Return a 2D array representation of the query, for simpler parsing.\n    // Example:\n    // \"^core go$ | rb$ | py$ xy$\" => [[\"^core\", \"go$\"], [\"rb$\"], [\"py$\", \"xy$\"]]\n    function parseQuery(pattern, options = {}) {\n      return pattern.split(OR_TOKEN).map(item => {\n        let query = item.trim().split(SPACE_RE).filter(item => item && !!item.trim());\n        let results = [];\n        for (let i = 0, len = query.length; i < len; i += 1) {\n          const queryItem = query[i];\n\n          // 1. Handle multiple query match (i.e, once that are quoted, like `\"hello world\"`)\n          let found = false;\n          let idx = -1;\n          while (!found && ++idx < searchersLen) {\n            const searcher = searchers[idx];\n            let token = searcher.isMultiMatch(queryItem);\n            if (token) {\n              results.push(new searcher(token, options));\n              found = true;\n            }\n          }\n          if (found) {\n            continue;\n          }\n\n          // 2. Handle single query matches (i.e, once that are *not* quoted)\n          idx = -1;\n          while (++idx < searchersLen) {\n            const searcher = searchers[idx];\n            let token = searcher.isSingleMatch(queryItem);\n            if (token) {\n              results.push(new searcher(token, options));\n              break;\n            }\n          }\n        }\n        return results;\n      });\n    }\n\n    // These extended matchers can return an array of matches, as opposed\n    // to a singl match\n    const MultiMatchSet = new Set([FuzzyMatch.type, IncludeMatch.type]);\n\n    /**\n     * Command-like searching\n     * ======================\n     *\n     * Given multiple search terms delimited by spaces.e.g. `^jscript .python$ ruby !java`,\n     * search in a given text.\n     *\n     * Search syntax:\n     *\n     * | Token       | Match type                 | Description                            |\n     * | ----------- | -------------------------- | -------------------------------------- |\n     * | `jscript`   | fuzzy-match                | Items that fuzzy match `jscript`       |\n     * | `=scheme`   | exact-match                | Items that are `scheme`                |\n     * | `'python`   | include-match              | Items that include `python`            |\n     * | `!ruby`     | inverse-exact-match        | Items that do not include `ruby`       |\n     * | `^java`     | prefix-exact-match         | Items that start with `java`           |\n     * | `!^earlang` | inverse-prefix-exact-match | Items that do not start with `earlang` |\n     * | `.js$`      | suffix-exact-match         | Items that end with `.js`              |\n     * | `!.go$`     | inverse-suffix-exact-match | Items that do not end with `.go`       |\n     *\n     * A single pipe character acts as an OR operator. For example, the following\n     * query matches entries that start with `core` and end with either`go`, `rb`,\n     * or`py`.\n     *\n     * ```\n     * ^core go$ | rb$ | py$\n     * ```\n     */\n    class ExtendedSearch {\n      constructor(pattern, {\n        isCaseSensitive = Config.isCaseSensitive,\n        includeMatches = Config.includeMatches,\n        minMatchCharLength = Config.minMatchCharLength,\n        ignoreLocation = Config.ignoreLocation,\n        findAllMatches = Config.findAllMatches,\n        location = Config.location,\n        threshold = Config.threshold,\n        distance = Config.distance\n      } = {}) {\n        this.query = null;\n        this.options = {\n          isCaseSensitive,\n          includeMatches,\n          minMatchCharLength,\n          findAllMatches,\n          ignoreLocation,\n          location,\n          threshold,\n          distance\n        };\n        this.pattern = isCaseSensitive ? pattern : pattern.toLowerCase();\n        this.query = parseQuery(this.pattern, this.options);\n      }\n      static condition(_, options) {\n        return options.useExtendedSearch;\n      }\n      searchIn(text) {\n        const query = this.query;\n        if (!query) {\n          return {\n            isMatch: false,\n            score: 1\n          };\n        }\n        const {\n          includeMatches,\n          isCaseSensitive\n        } = this.options;\n        text = isCaseSensitive ? text : text.toLowerCase();\n        let numMatches = 0;\n        let allIndices = [];\n        let totalScore = 0;\n\n        // ORs\n        for (let i = 0, qLen = query.length; i < qLen; i += 1) {\n          const searchers = query[i];\n\n          // Reset indices\n          allIndices.length = 0;\n          numMatches = 0;\n\n          // ANDs\n          for (let j = 0, pLen = searchers.length; j < pLen; j += 1) {\n            const searcher = searchers[j];\n            const {\n              isMatch,\n              indices,\n              score\n            } = searcher.search(text);\n            if (isMatch) {\n              numMatches += 1;\n              totalScore += score;\n              if (includeMatches) {\n                const type = searcher.constructor.type;\n                if (MultiMatchSet.has(type)) {\n                  allIndices = [...allIndices, ...indices];\n                } else {\n                  allIndices.push(indices);\n                }\n              }\n            } else {\n              totalScore = 0;\n              numMatches = 0;\n              allIndices.length = 0;\n              break;\n            }\n          }\n\n          // OR condition, so if TRUE, return\n          if (numMatches) {\n            let result = {\n              isMatch: true,\n              score: totalScore / numMatches\n            };\n            if (includeMatches) {\n              result.indices = allIndices;\n            }\n            return result;\n          }\n        }\n\n        // Nothing was matched\n        return {\n          isMatch: false,\n          score: 1\n        };\n      }\n    }\n    const registeredSearchers = [];\n    function register(...args) {\n      registeredSearchers.push(...args);\n    }\n    function createSearcher(pattern, options) {\n      for (let i = 0, len = registeredSearchers.length; i < len; i += 1) {\n        let searcherClass = registeredSearchers[i];\n        if (searcherClass.condition(pattern, options)) {\n          return new searcherClass(pattern, options);\n        }\n      }\n      return new BitapSearch(pattern, options);\n    }\n    const LogicalOperator = {\n      AND: '$and',\n      OR: '$or'\n    };\n    const KeyType = {\n      PATH: '$path',\n      PATTERN: '$val'\n    };\n    const isExpression = query => !!(query[LogicalOperator.AND] || query[LogicalOperator.OR]);\n    const isPath = query => !!query[KeyType.PATH];\n    const isLeaf = query => !isArray(query) && isObject(query) && !isExpression(query);\n    const convertToExplicit = query => ({\n      [LogicalOperator.AND]: Object.keys(query).map(key => ({\n        [key]: query[key]\n      }))\n    });\n\n    // When `auto` is `true`, the parse function will infer and initialize and add\n    // the appropriate `Searcher` instance\n    function parse(query, options, {\n      auto = true\n    } = {}) {\n      const next = query => {\n        let keys = Object.keys(query);\n        const isQueryPath = isPath(query);\n        if (!isQueryPath && keys.length > 1 && !isExpression(query)) {\n          return next(convertToExplicit(query));\n        }\n        if (isLeaf(query)) {\n          const key = isQueryPath ? query[KeyType.PATH] : keys[0];\n          const pattern = isQueryPath ? query[KeyType.PATTERN] : query[key];\n          if (!isString(pattern)) {\n            throw new Error(LOGICAL_SEARCH_INVALID_QUERY_FOR_KEY(key));\n          }\n          const obj = {\n            keyId: createKeyId(key),\n            pattern\n          };\n          if (auto) {\n            obj.searcher = createSearcher(pattern, options);\n          }\n          return obj;\n        }\n        let node = {\n          children: [],\n          operator: keys[0]\n        };\n        keys.forEach(key => {\n          const value = query[key];\n          if (isArray(value)) {\n            value.forEach(item => {\n              node.children.push(next(item));\n            });\n          }\n        });\n        return node;\n      };\n      if (!isExpression(query)) {\n        query = convertToExplicit(query);\n      }\n      return next(query);\n    }\n\n    // Practical scoring function\n    function computeScore(results, {\n      ignoreFieldNorm = Config.ignoreFieldNorm\n    }) {\n      results.forEach(result => {\n        let totalScore = 1;\n        result.matches.forEach(({\n          key,\n          norm,\n          score\n        }) => {\n          const weight = key ? key.weight : null;\n          totalScore *= Math.pow(score === 0 && weight ? Number.EPSILON : score, (weight || 1) * (ignoreFieldNorm ? 1 : norm));\n        });\n        result.score = totalScore;\n      });\n    }\n    function transformMatches(result, data) {\n      const matches = result.matches;\n      data.matches = [];\n      if (!isDefined(matches)) {\n        return;\n      }\n      matches.forEach(match => {\n        if (!isDefined(match.indices) || !match.indices.length) {\n          return;\n        }\n        const {\n          indices,\n          value\n        } = match;\n        let obj = {\n          indices,\n          value\n        };\n        if (match.key) {\n          obj.key = match.key.src;\n        }\n        if (match.idx > -1) {\n          obj.refIndex = match.idx;\n        }\n        data.matches.push(obj);\n      });\n    }\n    function transformScore(result, data) {\n      data.score = result.score;\n    }\n    function format(results, docs, {\n      includeMatches = Config.includeMatches,\n      includeScore = Config.includeScore\n    } = {}) {\n      const transformers = [];\n      if (includeMatches) transformers.push(transformMatches);\n      if (includeScore) transformers.push(transformScore);\n      return results.map(result => {\n        const {\n          idx\n        } = result;\n        const data = {\n          item: docs[idx],\n          refIndex: idx\n        };\n        if (transformers.length) {\n          transformers.forEach(transformer => {\n            transformer(result, data);\n          });\n        }\n        return data;\n      });\n    }\n    class Fuse {\n      constructor(docs, options = {}, index) {\n        this.options = _objectSpread2(_objectSpread2({}, Config), options);\n        if (this.options.useExtendedSearch && false) ;\n        this._keyStore = new KeyStore(this.options.keys);\n        this.setCollection(docs, index);\n      }\n      setCollection(docs, index) {\n        this._docs = docs;\n        if (index && !(index instanceof FuseIndex)) {\n          throw new Error(INCORRECT_INDEX_TYPE);\n        }\n        this._myIndex = index || createIndex(this.options.keys, this._docs, {\n          getFn: this.options.getFn,\n          fieldNormWeight: this.options.fieldNormWeight\n        });\n      }\n      add(doc) {\n        if (!isDefined(doc)) {\n          return;\n        }\n        this._docs.push(doc);\n        this._myIndex.add(doc);\n      }\n      remove(predicate = ( /* doc, idx */) => false) {\n        const results = [];\n        for (let i = 0, len = this._docs.length; i < len; i += 1) {\n          const doc = this._docs[i];\n          if (predicate(doc, i)) {\n            this.removeAt(i);\n            i -= 1;\n            len -= 1;\n            results.push(doc);\n          }\n        }\n        return results;\n      }\n      removeAt(idx) {\n        this._docs.splice(idx, 1);\n        this._myIndex.removeAt(idx);\n      }\n      getIndex() {\n        return this._myIndex;\n      }\n      search(query, {\n        limit = -1\n      } = {}) {\n        const {\n          includeMatches,\n          includeScore,\n          shouldSort,\n          sortFn,\n          ignoreFieldNorm\n        } = this.options;\n        let results = isString(query) ? isString(this._docs[0]) ? this._searchStringList(query) : this._searchObjectList(query) : this._searchLogical(query);\n        computeScore(results, {\n          ignoreFieldNorm\n        });\n        if (shouldSort) {\n          results.sort(sortFn);\n        }\n        if (isNumber(limit) && limit > -1) {\n          results = results.slice(0, limit);\n        }\n        return format(results, this._docs, {\n          includeMatches,\n          includeScore\n        });\n      }\n      _searchStringList(query) {\n        const searcher = createSearcher(query, this.options);\n        const {\n          records\n        } = this._myIndex;\n        const results = [];\n\n        // Iterate over every string in the index\n        records.forEach(({\n          v: text,\n          i: idx,\n          n: norm\n        }) => {\n          if (!isDefined(text)) {\n            return;\n          }\n          const {\n            isMatch,\n            score,\n            indices\n          } = searcher.searchIn(text);\n          if (isMatch) {\n            results.push({\n              item: text,\n              idx,\n              matches: [{\n                score,\n                value: text,\n                norm,\n                indices\n              }]\n            });\n          }\n        });\n        return results;\n      }\n      _searchLogical(query) {\n        const expression = parse(query, this.options);\n        const evaluate = (node, item, idx) => {\n          if (!node.children) {\n            const {\n              keyId,\n              searcher\n            } = node;\n            const matches = this._findMatches({\n              key: this._keyStore.get(keyId),\n              value: this._myIndex.getValueForItemAtKeyId(item, keyId),\n              searcher\n            });\n            if (matches && matches.length) {\n              return [{\n                idx,\n                item,\n                matches\n              }];\n            }\n            return [];\n          }\n          const res = [];\n          for (let i = 0, len = node.children.length; i < len; i += 1) {\n            const child = node.children[i];\n            const result = evaluate(child, item, idx);\n            if (result.length) {\n              res.push(...result);\n            } else if (node.operator === LogicalOperator.AND) {\n              return [];\n            }\n          }\n          return res;\n        };\n        const records = this._myIndex.records;\n        const resultMap = {};\n        const results = [];\n        records.forEach(({\n          $: item,\n          i: idx\n        }) => {\n          if (isDefined(item)) {\n            let expResults = evaluate(expression, item, idx);\n            if (expResults.length) {\n              // Dedupe when adding\n              if (!resultMap[idx]) {\n                resultMap[idx] = {\n                  idx,\n                  item,\n                  matches: []\n                };\n                results.push(resultMap[idx]);\n              }\n              expResults.forEach(({\n                matches\n              }) => {\n                resultMap[idx].matches.push(...matches);\n              });\n            }\n          }\n        });\n        return results;\n      }\n      _searchObjectList(query) {\n        const searcher = createSearcher(query, this.options);\n        const {\n          keys,\n          records\n        } = this._myIndex;\n        const results = [];\n\n        // List is Array<Object>\n        records.forEach(({\n          $: item,\n          i: idx\n        }) => {\n          if (!isDefined(item)) {\n            return;\n          }\n          let matches = [];\n\n          // Iterate over every key (i.e, path), and fetch the value at that key\n          keys.forEach((key, keyIndex) => {\n            matches.push(...this._findMatches({\n              key,\n              value: item[keyIndex],\n              searcher\n            }));\n          });\n          if (matches.length) {\n            results.push({\n              idx,\n              item,\n              matches\n            });\n          }\n        });\n        return results;\n      }\n      _findMatches({\n        key,\n        value,\n        searcher\n      }) {\n        if (!isDefined(value)) {\n          return [];\n        }\n        let matches = [];\n        if (isArray(value)) {\n          value.forEach(({\n            v: text,\n            i: idx,\n            n: norm\n          }) => {\n            if (!isDefined(text)) {\n              return;\n            }\n            const {\n              isMatch,\n              score,\n              indices\n            } = searcher.searchIn(text);\n            if (isMatch) {\n              matches.push({\n                score,\n                key,\n                value: text,\n                idx,\n                norm,\n                indices\n              });\n            }\n          });\n        } else {\n          const {\n            v: text,\n            n: norm\n          } = value;\n          const {\n            isMatch,\n            score,\n            indices\n          } = searcher.searchIn(text);\n          if (isMatch) {\n            matches.push({\n              score,\n              key,\n              value: text,\n              norm,\n              indices\n            });\n          }\n        }\n        return matches;\n      }\n    }\n    Fuse.version = '7.0.0';\n    Fuse.createIndex = createIndex;\n    Fuse.parseIndex = parseIndex;\n    Fuse.config = Config;\n    {\n      Fuse.parseQuery = parse;\n    }\n    {\n      register(ExtendedSearch);\n    }\n\n    var SearchByFuse = /** @class */ (function () {\n        function SearchByFuse(config) {\n            this._haystack = [];\n            this._fuseOptions = __assign(__assign({}, config.fuseOptions), { keys: __spreadArray([], config.searchFields, true), includeMatches: true });\n        }\n        SearchByFuse.prototype.index = function (data) {\n            this._haystack = data;\n            if (this._fuse) {\n                this._fuse.setCollection(data);\n            }\n        };\n        SearchByFuse.prototype.reset = function () {\n            this._haystack = [];\n            this._fuse = undefined;\n        };\n        SearchByFuse.prototype.isEmptyIndex = function () {\n            return !this._haystack.length;\n        };\n        SearchByFuse.prototype.search = function (needle) {\n            if (!this._fuse) {\n                {\n                    this._fuse = new Fuse(this._haystack, this._fuseOptions);\n                }\n            }\n            var results = this._fuse.search(needle);\n            return results.map(function (value, i) {\n                return {\n                    item: value.item,\n                    score: value.score || 0,\n                    rank: i + 1, // If value.score is used for sorting, this can create non-stable sorts!\n                };\n            });\n        };\n        return SearchByFuse;\n    }());\n\n    function getSearcher(config) {\n        {\n            return new SearchByFuse(config);\n        }\n    }\n\n    /**\n     * Helpers to create HTML elements used by Choices\n     * Can be overridden by providing `callbackOnCreateTemplates` option.\n     * `Choices.defaults.templates` allows access to the default template methods from `callbackOnCreateTemplates`\n     */\n    var isEmptyObject = function (obj) {\n        // eslint-disable-next-line no-restricted-syntax\n        for (var prop in obj) {\n            if (Object.prototype.hasOwnProperty.call(obj, prop)) {\n                return false;\n            }\n        }\n        return true;\n    };\n    var assignCustomProperties = function (el, choice, withCustomProperties) {\n        var dataset = el.dataset;\n        var customProperties = choice.customProperties, labelClass = choice.labelClass, labelDescription = choice.labelDescription;\n        if (labelClass) {\n            dataset.labelClass = getClassNames(labelClass).join(' ');\n        }\n        if (labelDescription) {\n            dataset.labelDescription = unwrapStringForRaw(labelDescription);\n        }\n        if (withCustomProperties && customProperties) {\n            if (typeof customProperties === 'string') {\n                dataset.customProperties = customProperties;\n            }\n            else if (typeof customProperties === 'object' && !isEmptyObject(customProperties)) {\n                dataset.customProperties = JSON.stringify(customProperties);\n            }\n        }\n    };\n    var addAriaLabel = function (docRoot, id, element) {\n        var label = id && docRoot.querySelector(\"label[for='\".concat(id, \"']\"));\n        var text = label && label.innerText;\n        if (text) {\n            element.setAttribute('aria-label', text);\n        }\n    };\n    var templates = {\n        containerOuter: function (_a, dir, isSelectElement, isSelectOneElement, searchEnabled, passedElementType, labelId) {\n            var containerOuter = _a.classNames.containerOuter;\n            var div = document.createElement('div');\n            addClassesToElement(div, containerOuter);\n            div.dataset.type = passedElementType;\n            if (dir) {\n                div.dir = dir;\n            }\n            if (isSelectOneElement) {\n                div.tabIndex = 0;\n            }\n            if (isSelectElement) {\n                div.setAttribute('role', searchEnabled ? 'combobox' : 'listbox');\n                if (searchEnabled) {\n                    div.setAttribute('aria-autocomplete', 'list');\n                }\n                else if (!labelId) {\n                    addAriaLabel(this._docRoot, this.passedElement.element.id, div);\n                }\n                div.setAttribute('aria-haspopup', 'true');\n                div.setAttribute('aria-expanded', 'false');\n            }\n            if (labelId) {\n                div.setAttribute('aria-labelledby', labelId);\n            }\n            return div;\n        },\n        containerInner: function (_a) {\n            var containerInner = _a.classNames.containerInner;\n            var div = document.createElement('div');\n            addClassesToElement(div, containerInner);\n            return div;\n        },\n        itemList: function (_a, isSelectOneElement) {\n            var searchEnabled = _a.searchEnabled, _b = _a.classNames, list = _b.list, listSingle = _b.listSingle, listItems = _b.listItems;\n            var div = document.createElement('div');\n            addClassesToElement(div, list);\n            addClassesToElement(div, isSelectOneElement ? listSingle : listItems);\n            if (this._isSelectElement && searchEnabled) {\n                div.setAttribute('role', 'listbox');\n            }\n            return div;\n        },\n        placeholder: function (_a, value) {\n            var allowHTML = _a.allowHTML, placeholder = _a.classNames.placeholder;\n            var div = document.createElement('div');\n            addClassesToElement(div, placeholder);\n            setElementHtml(div, allowHTML, value);\n            return div;\n        },\n        item: function (_a, choice, removeItemButton) {\n            var allowHTML = _a.allowHTML, removeItemButtonAlignLeft = _a.removeItemButtonAlignLeft, removeItemIconText = _a.removeItemIconText, removeItemLabelText = _a.removeItemLabelText, _b = _a.classNames, item = _b.item, button = _b.button, highlightedState = _b.highlightedState, itemSelectable = _b.itemSelectable, placeholder = _b.placeholder;\n            var rawValue = unwrapStringForRaw(choice.value);\n            var div = document.createElement('div');\n            addClassesToElement(div, item);\n            if (choice.labelClass) {\n                var spanLabel = document.createElement('span');\n                setElementHtml(spanLabel, allowHTML, choice.label);\n                addClassesToElement(spanLabel, choice.labelClass);\n                div.appendChild(spanLabel);\n            }\n            else {\n                setElementHtml(div, allowHTML, choice.label);\n            }\n            div.dataset.item = '';\n            div.dataset.id = choice.id;\n            div.dataset.value = rawValue;\n            assignCustomProperties(div, choice, true);\n            if (choice.disabled || this.containerOuter.isDisabled) {\n                div.setAttribute('aria-disabled', 'true');\n            }\n            if (this._isSelectElement) {\n                div.setAttribute('aria-selected', 'true');\n                div.setAttribute('role', 'option');\n            }\n            if (choice.placeholder) {\n                addClassesToElement(div, placeholder);\n                div.dataset.placeholder = '';\n            }\n            addClassesToElement(div, choice.highlighted ? highlightedState : itemSelectable);\n            if (removeItemButton) {\n                if (choice.disabled) {\n                    removeClassesFromElement(div, itemSelectable);\n                }\n                div.dataset.deletable = '';\n                var removeButton = document.createElement('button');\n                removeButton.type = 'button';\n                addClassesToElement(removeButton, button);\n                var eventChoice = getChoiceForOutput(choice);\n                setElementHtml(removeButton, true, resolveNoticeFunction(removeItemIconText, choice.value, eventChoice));\n                var REMOVE_ITEM_LABEL = resolveNoticeFunction(removeItemLabelText, choice.value, eventChoice);\n                if (REMOVE_ITEM_LABEL) {\n                    removeButton.setAttribute('aria-label', REMOVE_ITEM_LABEL);\n                }\n                removeButton.dataset.button = '';\n                if (removeItemButtonAlignLeft) {\n                    div.insertAdjacentElement('afterbegin', removeButton);\n                }\n                else {\n                    div.appendChild(removeButton);\n                }\n            }\n            return div;\n        },\n        choiceList: function (_a, isSelectOneElement) {\n            var list = _a.classNames.list;\n            var div = document.createElement('div');\n            addClassesToElement(div, list);\n            if (!isSelectOneElement) {\n                div.setAttribute('aria-multiselectable', 'true');\n            }\n            div.setAttribute('role', 'listbox');\n            return div;\n        },\n        choiceGroup: function (_a, _b) {\n            var allowHTML = _a.allowHTML, _c = _a.classNames, group = _c.group, groupHeading = _c.groupHeading, itemDisabled = _c.itemDisabled;\n            var id = _b.id, label = _b.label, disabled = _b.disabled;\n            var rawLabel = unwrapStringForRaw(label);\n            var div = document.createElement('div');\n            addClassesToElement(div, group);\n            if (disabled) {\n                addClassesToElement(div, itemDisabled);\n            }\n            div.setAttribute('role', 'group');\n            div.dataset.group = '';\n            div.dataset.id = id;\n            div.dataset.value = rawLabel;\n            if (disabled) {\n                div.setAttribute('aria-disabled', 'true');\n            }\n            var heading = document.createElement('div');\n            addClassesToElement(heading, groupHeading);\n            setElementHtml(heading, allowHTML, label || '');\n            div.appendChild(heading);\n            return div;\n        },\n        choice: function (_a, choice, selectText, groupName) {\n            var allowHTML = _a.allowHTML, _b = _a.classNames, item = _b.item, itemChoice = _b.itemChoice, itemSelectable = _b.itemSelectable, selectedState = _b.selectedState, itemDisabled = _b.itemDisabled, description = _b.description, placeholder = _b.placeholder;\n            // eslint-disable-next-line prefer-destructuring\n            var label = choice.label;\n            var rawValue = unwrapStringForRaw(choice.value);\n            var div = document.createElement('div');\n            div.id = choice.elementId;\n            addClassesToElement(div, item);\n            addClassesToElement(div, itemChoice);\n            if (groupName && typeof label === 'string') {\n                label = escapeForTemplate(allowHTML, label);\n                label += \" (\".concat(groupName, \")\");\n                label = { trusted: label };\n            }\n            var describedBy = div;\n            if (choice.labelClass) {\n                var spanLabel = document.createElement('span');\n                setElementHtml(spanLabel, allowHTML, label);\n                addClassesToElement(spanLabel, choice.labelClass);\n                describedBy = spanLabel;\n                div.appendChild(spanLabel);\n            }\n            else {\n                setElementHtml(div, allowHTML, label);\n            }\n            if (choice.labelDescription) {\n                var descId = \"\".concat(choice.elementId, \"-description\");\n                describedBy.setAttribute('aria-describedby', descId);\n                var spanDesc = document.createElement('span');\n                setElementHtml(spanDesc, allowHTML, choice.labelDescription);\n                spanDesc.id = descId;\n                addClassesToElement(spanDesc, description);\n                div.appendChild(spanDesc);\n            }\n            if (choice.selected) {\n                addClassesToElement(div, selectedState);\n            }\n            if (choice.placeholder) {\n                addClassesToElement(div, placeholder);\n            }\n            div.setAttribute('role', choice.group ? 'treeitem' : 'option');\n            div.dataset.choice = '';\n            div.dataset.id = choice.id;\n            div.dataset.value = rawValue;\n            if (selectText) {\n                div.dataset.selectText = selectText;\n            }\n            if (choice.group) {\n                div.dataset.groupId = \"\".concat(choice.group.id);\n            }\n            assignCustomProperties(div, choice, false);\n            if (choice.disabled) {\n                addClassesToElement(div, itemDisabled);\n                div.dataset.choiceDisabled = '';\n                div.setAttribute('aria-disabled', 'true');\n            }\n            else {\n                addClassesToElement(div, itemSelectable);\n                div.dataset.choiceSelectable = '';\n                div.setAttribute('aria-selected', choice.selected ? 'true' : 'false');\n            }\n            return div;\n        },\n        input: function (_a, placeholderValue) {\n            var _b = _a.classNames, input = _b.input, inputCloned = _b.inputCloned, labelId = _a.labelId;\n            var inp = document.createElement('input');\n            inp.type = 'search';\n            addClassesToElement(inp, input);\n            addClassesToElement(inp, inputCloned);\n            inp.autocomplete = 'off';\n            inp.autocapitalize = 'off';\n            inp.spellcheck = false;\n            inp.setAttribute('aria-autocomplete', 'list');\n            if (placeholderValue) {\n                inp.setAttribute('aria-label', placeholderValue);\n            }\n            else if (!labelId) {\n                addAriaLabel(this._docRoot, this.passedElement.element.id, inp);\n            }\n            return inp;\n        },\n        dropdown: function (_a) {\n            var _b = _a.classNames, list = _b.list, listDropdown = _b.listDropdown;\n            var div = document.createElement('div');\n            addClassesToElement(div, list);\n            addClassesToElement(div, listDropdown);\n            div.setAttribute('aria-expanded', 'false');\n            return div;\n        },\n        notice: function (_a, innerHTML, type) {\n            var _b = _a.classNames, item = _b.item, itemChoice = _b.itemChoice, addChoice = _b.addChoice, noResults = _b.noResults, noChoices = _b.noChoices, noticeItem = _b.notice;\n            if (type === void 0) { type = NoticeTypes.generic; }\n            var notice = document.createElement('div');\n            setElementHtml(notice, true, innerHTML);\n            addClassesToElement(notice, item);\n            addClassesToElement(notice, itemChoice);\n            addClassesToElement(notice, noticeItem);\n            // eslint-disable-next-line default-case\n            switch (type) {\n                case NoticeTypes.addChoice:\n                    addClassesToElement(notice, addChoice);\n                    break;\n                case NoticeTypes.noResults:\n                    addClassesToElement(notice, noResults);\n                    break;\n                case NoticeTypes.noChoices:\n                    addClassesToElement(notice, noChoices);\n                    break;\n            }\n            if (type === NoticeTypes.addChoice) {\n                notice.dataset.choiceSelectable = '';\n                notice.dataset.choice = '';\n            }\n            return notice;\n        },\n        option: function (choice) {\n            // HtmlOptionElement's label value does not support HTML, so the avoid double escaping unwrap the untrusted string.\n            var labelValue = unwrapStringForRaw(choice.label);\n            var opt = new Option(labelValue, choice.value, false, choice.selected);\n            assignCustomProperties(opt, choice, true);\n            opt.disabled = choice.disabled;\n            if (choice.selected) {\n                opt.setAttribute('selected', '');\n            }\n            return opt;\n        },\n    };\n\n    /** @see {@link http://browserhacks.com/#hack-acea075d0ac6954f275a70023906050c} */\n    var IS_IE11 = '-ms-scroll-limit' in document.documentElement.style &&\n        '-ms-ime-align' in document.documentElement.style;\n    var USER_DEFAULTS = {};\n    var parseDataSetId = function (element) {\n        if (!element) {\n            return undefined;\n        }\n        return element.dataset.id ? parseInt(element.dataset.id, 10) : undefined;\n    };\n    var selectableChoiceIdentifier = '[data-choice-selectable]';\n    /**\n     * Choices\n     * @author Josh Johnson<josh@joshuajohnson.co.uk>\n     */\n    var Choices = /** @class */ (function () {\n        function Choices(element, userConfig) {\n            if (element === void 0) { element = '[data-choice]'; }\n            if (userConfig === void 0) { userConfig = {}; }\n            var _this = this;\n            this.initialisedOK = undefined;\n            this._hasNonChoicePlaceholder = false;\n            this._lastAddedChoiceId = 0;\n            this._lastAddedGroupId = 0;\n            var defaults = Choices.defaults;\n            this.config = __assign(__assign(__assign({}, defaults.allOptions), defaults.options), userConfig);\n            ObjectsInConfig.forEach(function (key) {\n                _this.config[key] = __assign(__assign(__assign({}, defaults.allOptions[key]), defaults.options[key]), userConfig[key]);\n            });\n            var config = this.config;\n            if (!config.silent) {\n                this._validateConfig();\n            }\n            var docRoot = config.shadowRoot || document.documentElement;\n            this._docRoot = docRoot;\n            var passedElement = typeof element === 'string' ? docRoot.querySelector(element) : element;\n            if (!passedElement ||\n                typeof passedElement !== 'object' ||\n                !(isHtmlInputElement(passedElement) || isHtmlSelectElement(passedElement))) {\n                if (!passedElement && typeof element === 'string') {\n                    throw TypeError(\"Selector \".concat(element, \" failed to find an element\"));\n                }\n                throw TypeError(\"Expected one of the following types text|select-one|select-multiple\");\n            }\n            var elementType = passedElement.type;\n            var isText = elementType === PassedElementTypes.Text;\n            if (isText || config.maxItemCount !== 1) {\n                config.singleModeForMultiSelect = false;\n            }\n            if (config.singleModeForMultiSelect) {\n                elementType = PassedElementTypes.SelectMultiple;\n            }\n            var isSelectOne = elementType === PassedElementTypes.SelectOne;\n            var isSelectMultiple = elementType === PassedElementTypes.SelectMultiple;\n            var isSelect = isSelectOne || isSelectMultiple;\n            this._elementType = elementType;\n            this._isTextElement = isText;\n            this._isSelectOneElement = isSelectOne;\n            this._isSelectMultipleElement = isSelectMultiple;\n            this._isSelectElement = isSelectOne || isSelectMultiple;\n            this._canAddUserChoices = (isText && config.addItems) || (isSelect && config.addChoices);\n            if (typeof config.renderSelectedChoices !== 'boolean') {\n                config.renderSelectedChoices = config.renderSelectedChoices === 'always' || isSelectOne;\n            }\n            if (config.closeDropdownOnSelect === 'auto') {\n                config.closeDropdownOnSelect = isText || isSelectOne || config.singleModeForMultiSelect;\n            }\n            else {\n                config.closeDropdownOnSelect = coerceBool(config.closeDropdownOnSelect);\n            }\n            if (config.placeholder) {\n                if (config.placeholderValue) {\n                    this._hasNonChoicePlaceholder = true;\n                }\n                else if (passedElement.dataset.placeholder) {\n                    this._hasNonChoicePlaceholder = true;\n                    config.placeholderValue = passedElement.dataset.placeholder;\n                }\n            }\n            if (userConfig.addItemFilter && typeof userConfig.addItemFilter !== 'function') {\n                var re = userConfig.addItemFilter instanceof RegExp ? userConfig.addItemFilter : new RegExp(userConfig.addItemFilter);\n                config.addItemFilter = re.test.bind(re);\n            }\n            if (this._isTextElement) {\n                this.passedElement = new WrappedInput({\n                    element: passedElement,\n                    classNames: config.classNames,\n                });\n            }\n            else {\n                var selectEl = passedElement;\n                this.passedElement = new WrappedSelect({\n                    element: selectEl,\n                    classNames: config.classNames,\n                    template: function (data) { return _this._templates.option(data); },\n                    extractPlaceholder: config.placeholder && !this._hasNonChoicePlaceholder,\n                });\n            }\n            this.initialised = false;\n            this._store = new Store(config);\n            this._currentValue = '';\n            config.searchEnabled = !isText && config.searchEnabled;\n            this._canSearch = config.searchEnabled;\n            this._isScrollingOnIe = false;\n            this._highlightPosition = 0;\n            this._wasTap = true;\n            this._placeholderValue = this._generatePlaceholderValue();\n            this._baseId = generateId(passedElement, 'choices-');\n            /**\n             * setting direction in cases where it's explicitly set on passedElement\n             * or when calculated direction is different from the document\n             */\n            this._direction = passedElement.dir;\n            if (!this._direction) {\n                var elementDirection = window.getComputedStyle(passedElement).direction;\n                var documentDirection = window.getComputedStyle(document.documentElement).direction;\n                if (elementDirection !== documentDirection) {\n                    this._direction = elementDirection;\n                }\n            }\n            this._idNames = {\n                itemChoice: 'item-choice',\n            };\n            this._templates = defaults.templates;\n            this._render = this._render.bind(this);\n            this._onFocus = this._onFocus.bind(this);\n            this._onBlur = this._onBlur.bind(this);\n            this._onKeyUp = this._onKeyUp.bind(this);\n            this._onKeyDown = this._onKeyDown.bind(this);\n            this._onInput = this._onInput.bind(this);\n            this._onClick = this._onClick.bind(this);\n            this._onTouchMove = this._onTouchMove.bind(this);\n            this._onTouchEnd = this._onTouchEnd.bind(this);\n            this._onMouseDown = this._onMouseDown.bind(this);\n            this._onMouseOver = this._onMouseOver.bind(this);\n            this._onFormReset = this._onFormReset.bind(this);\n            this._onSelectKey = this._onSelectKey.bind(this);\n            this._onEnterKey = this._onEnterKey.bind(this);\n            this._onEscapeKey = this._onEscapeKey.bind(this);\n            this._onDirectionKey = this._onDirectionKey.bind(this);\n            this._onDeleteKey = this._onDeleteKey.bind(this);\n            this._onChange = this._onChange.bind(this);\n            this._onInvalid = this._onInvalid.bind(this);\n            // If element has already been initialised with Choices, fail silently\n            if (this.passedElement.isActive) {\n                if (!config.silent) {\n                    console.warn('Trying to initialise Choices on element already initialised', { element: element });\n                }\n                this.initialised = true;\n                this.initialisedOK = false;\n                return;\n            }\n            // Let's go\n            this.init();\n            // preserve the selected item list after setup for form reset\n            this._initialItems = this._store.items.map(function (choice) { return choice.value; });\n        }\n        Object.defineProperty(Choices, \"defaults\", {\n            get: function () {\n                return Object.preventExtensions({\n                    get options() {\n                        return USER_DEFAULTS;\n                    },\n                    get allOptions() {\n                        return DEFAULT_CONFIG;\n                    },\n                    get templates() {\n                        return templates;\n                    },\n                });\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Choices.prototype.init = function () {\n            if (this.initialised || this.initialisedOK !== undefined) {\n                return;\n            }\n            this._searcher = getSearcher(this.config);\n            this._loadChoices();\n            this._createTemplates();\n            this._createElements();\n            this._createStructure();\n            if ((this._isTextElement && !this.config.addItems) ||\n                this.passedElement.element.hasAttribute('disabled') ||\n                !!this.passedElement.element.closest('fieldset:disabled')) {\n                this.disable();\n            }\n            else {\n                this.enable();\n                this._addEventListeners();\n            }\n            // should be triggered **after** disabled state to avoid additional re-draws\n            this._initStore();\n            this.initialised = true;\n            this.initialisedOK = true;\n            var callbackOnInit = this.config.callbackOnInit;\n            // Run callback if it is a function\n            if (typeof callbackOnInit === 'function') {\n                callbackOnInit.call(this);\n            }\n        };\n        Choices.prototype.destroy = function () {\n            if (!this.initialised) {\n                return;\n            }\n            this._removeEventListeners();\n            this.passedElement.reveal();\n            this.containerOuter.unwrap(this.passedElement.element);\n            this._store._listeners = []; // prevents select/input value being wiped\n            this.clearStore(false);\n            this._stopSearch();\n            this._templates = Choices.defaults.templates;\n            this.initialised = false;\n            this.initialisedOK = undefined;\n        };\n        Choices.prototype.enable = function () {\n            if (this.passedElement.isDisabled) {\n                this.passedElement.enable();\n            }\n            if (this.containerOuter.isDisabled) {\n                this._addEventListeners();\n                this.input.enable();\n                this.containerOuter.enable();\n            }\n            return this;\n        };\n        Choices.prototype.disable = function () {\n            if (!this.passedElement.isDisabled) {\n                this.passedElement.disable();\n            }\n            if (!this.containerOuter.isDisabled) {\n                this._removeEventListeners();\n                this.input.disable();\n                this.containerOuter.disable();\n            }\n            return this;\n        };\n        Choices.prototype.highlightItem = function (item, runEvent) {\n            if (runEvent === void 0) { runEvent = true; }\n            if (!item || !item.id) {\n                return this;\n            }\n            var choice = this._store.items.find(function (c) { return c.id === item.id; });\n            if (!choice || choice.highlighted) {\n                return this;\n            }\n            this._store.dispatch(highlightItem(choice, true));\n            if (runEvent) {\n                this.passedElement.triggerEvent(EventType.highlightItem, getChoiceForOutput(choice));\n            }\n            return this;\n        };\n        Choices.prototype.unhighlightItem = function (item, runEvent) {\n            if (runEvent === void 0) { runEvent = true; }\n            if (!item || !item.id) {\n                return this;\n            }\n            var choice = this._store.items.find(function (c) { return c.id === item.id; });\n            if (!choice || !choice.highlighted) {\n                return this;\n            }\n            this._store.dispatch(highlightItem(choice, false));\n            if (runEvent) {\n                this.passedElement.triggerEvent(EventType.unhighlightItem, getChoiceForOutput(choice));\n            }\n            return this;\n        };\n        Choices.prototype.highlightAll = function () {\n            var _this = this;\n            this._store.withTxn(function () {\n                _this._store.items.forEach(function (item) {\n                    if (!item.highlighted) {\n                        _this._store.dispatch(highlightItem(item, true));\n                        _this.passedElement.triggerEvent(EventType.highlightItem, getChoiceForOutput(item));\n                    }\n                });\n            });\n            return this;\n        };\n        Choices.prototype.unhighlightAll = function () {\n            var _this = this;\n            this._store.withTxn(function () {\n                _this._store.items.forEach(function (item) {\n                    if (item.highlighted) {\n                        _this._store.dispatch(highlightItem(item, false));\n                        _this.passedElement.triggerEvent(EventType.highlightItem, getChoiceForOutput(item));\n                    }\n                });\n            });\n            return this;\n        };\n        Choices.prototype.removeActiveItemsByValue = function (value) {\n            var _this = this;\n            this._store.withTxn(function () {\n                _this._store.items.filter(function (item) { return item.value === value; }).forEach(function (item) { return _this._removeItem(item); });\n            });\n            return this;\n        };\n        Choices.prototype.removeActiveItems = function (excludedId) {\n            var _this = this;\n            this._store.withTxn(function () {\n                _this._store.items.filter(function (_a) {\n                    var id = _a.id;\n                    return id !== excludedId;\n                }).forEach(function (item) { return _this._removeItem(item); });\n            });\n            return this;\n        };\n        Choices.prototype.removeHighlightedItems = function (runEvent) {\n            var _this = this;\n            if (runEvent === void 0) { runEvent = false; }\n            this._store.withTxn(function () {\n                _this._store.highlightedActiveItems.forEach(function (item) {\n                    _this._removeItem(item);\n                    // If this action was performed by the user\n                    // trigger the event\n                    if (runEvent) {\n                        _this._triggerChange(item.value);\n                    }\n                });\n            });\n            return this;\n        };\n        Choices.prototype.showDropdown = function (preventInputFocus) {\n            var _this = this;\n            if (this.dropdown.isActive) {\n                return this;\n            }\n            if (preventInputFocus === undefined) {\n                // eslint-disable-next-line no-param-reassign\n                preventInputFocus = !this._canSearch;\n            }\n            requestAnimationFrame(function () {\n                _this.dropdown.show();\n                var rect = _this.dropdown.element.getBoundingClientRect();\n                _this.containerOuter.open(rect.bottom, rect.height);\n                if (!preventInputFocus) {\n                    _this.input.focus();\n                }\n                _this.passedElement.triggerEvent(EventType.showDropdown);\n                var activeElement = _this.choiceList.element.querySelector(getClassNamesSelector(_this.config.classNames.selectedState));\n                if (activeElement !== null && !isScrolledIntoView(activeElement, _this.choiceList.element)) {\n                    // We use the native scrollIntoView function instead of choiceList.scrollToChildElement to avoid animated scroll.\n                    activeElement.scrollIntoView();\n                }\n            });\n            return this;\n        };\n        Choices.prototype.hideDropdown = function (preventInputBlur) {\n            var _this = this;\n            if (!this.dropdown.isActive) {\n                return this;\n            }\n            this._removeHighlightedChoices();\n            requestAnimationFrame(function () {\n                _this.dropdown.hide();\n                _this.containerOuter.close();\n                if (!preventInputBlur && _this._canSearch) {\n                    _this.input.removeActiveDescendant();\n                    _this.input.blur();\n                }\n                _this.passedElement.triggerEvent(EventType.hideDropdown);\n            });\n            return this;\n        };\n        Choices.prototype.getValue = function (valueOnly) {\n            var values = this._store.items.map(function (item) {\n                return (valueOnly ? item.value : getChoiceForOutput(item));\n            });\n            return this._isSelectOneElement || this.config.singleModeForMultiSelect ? values[0] : values;\n        };\n        Choices.prototype.setValue = function (items) {\n            var _this = this;\n            if (!this.initialisedOK) {\n                this._warnChoicesInitFailed('setValue');\n                return this;\n            }\n            this._store.withTxn(function () {\n                items.forEach(function (value) {\n                    if (value) {\n                        _this._addChoice(mapInputToChoice(value, false));\n                    }\n                });\n            });\n            // @todo integrate with Store\n            this._searcher.reset();\n            return this;\n        };\n        Choices.prototype.setChoiceByValue = function (value) {\n            var _this = this;\n            if (!this.initialisedOK) {\n                this._warnChoicesInitFailed('setChoiceByValue');\n                return this;\n            }\n            if (this._isTextElement) {\n                return this;\n            }\n            this._store.withTxn(function () {\n                // If only one value has been passed, convert to array\n                var choiceValue = Array.isArray(value) ? value : [value];\n                // Loop through each value and\n                choiceValue.forEach(function (val) { return _this._findAndSelectChoiceByValue(val); });\n                _this.unhighlightAll();\n            });\n            // @todo integrate with Store\n            this._searcher.reset();\n            return this;\n        };\n        /**\n         * Set choices of select input via an array of objects (or function that returns array of object or promise of it),\n         * a value field name and a label field name.\n         * This behaves the same as passing items via the choices option but can be called after initialising Choices.\n         * This can also be used to add groups of choices (see example 2); Optionally pass a true `replaceChoices` value to remove any existing choices.\n         * Optionally pass a `customProperties` object to add additional data to your choices (useful when searching/filtering etc).\n         *\n         * **Input types affected:** select-one, select-multiple\n         *\n         * @example\n         * ```js\n         * const example = new Choices(element);\n         *\n         * example.setChoices([\n         *   {value: 'One', label: 'Label One', disabled: true},\n         *   {value: 'Two', label: 'Label Two', selected: true},\n         *   {value: 'Three', label: 'Label Three'},\n         * ], 'value', 'label', false);\n         * ```\n         *\n         * @example\n         * ```js\n         * const example = new Choices(element);\n         *\n         * example.setChoices(async () => {\n         *   try {\n         *      const items = await fetch('/items');\n         *      return items.json()\n         *   } catch(err) {\n         *      console.error(err)\n         *   }\n         * });\n         * ```\n         *\n         * @example\n         * ```js\n         * const example = new Choices(element);\n         *\n         * example.setChoices([{\n         *   label: 'Group one',\n         *   id: 1,\n         *   disabled: false,\n         *   choices: [\n         *     {value: 'Child One', label: 'Child One', selected: true},\n         *     {value: 'Child Two', label: 'Child Two',  disabled: true},\n         *     {value: 'Child Three', label: 'Child Three'},\n         *   ]\n         * },\n         * {\n         *   label: 'Group two',\n         *   id: 2,\n         *   disabled: false,\n         *   choices: [\n         *     {value: 'Child Four', label: 'Child Four', disabled: true},\n         *     {value: 'Child Five', label: 'Child Five'},\n         *     {value: 'Child Six', label: 'Child Six', customProperties: {\n         *       description: 'Custom description about child six',\n         *       random: 'Another random custom property'\n         *     }},\n         *   ]\n         * }], 'value', 'label', false);\n         * ```\n         */\n        Choices.prototype.setChoices = function (choicesArrayOrFetcher, value, label, replaceChoices, clearSearchFlag, replaceItems) {\n            var _this = this;\n            if (choicesArrayOrFetcher === void 0) { choicesArrayOrFetcher = []; }\n            if (value === void 0) { value = 'value'; }\n            if (label === void 0) { label = 'label'; }\n            if (replaceChoices === void 0) { replaceChoices = false; }\n            if (clearSearchFlag === void 0) { clearSearchFlag = true; }\n            if (replaceItems === void 0) { replaceItems = false; }\n            if (!this.initialisedOK) {\n                this._warnChoicesInitFailed('setChoices');\n                return this;\n            }\n            if (!this._isSelectElement) {\n                throw new TypeError(\"setChoices can't be used with INPUT based Choices\");\n            }\n            if (typeof value !== 'string' || !value) {\n                throw new TypeError(\"value parameter must be a name of 'value' field in passed objects\");\n            }\n            if (typeof choicesArrayOrFetcher === 'function') {\n                // it's a choices fetcher function\n                var fetcher_1 = choicesArrayOrFetcher(this);\n                if (typeof Promise === 'function' && fetcher_1 instanceof Promise) {\n                    // that's a promise\n                    // eslint-disable-next-line no-promise-executor-return\n                    return new Promise(function (resolve) { return requestAnimationFrame(resolve); })\n                        .then(function () { return _this._handleLoadingState(true); })\n                        .then(function () { return fetcher_1; })\n                        .then(function (data) {\n                        return _this.setChoices(data, value, label, replaceChoices, clearSearchFlag, replaceItems);\n                    })\n                        .catch(function (err) {\n                        if (!_this.config.silent) {\n                            console.error(err);\n                        }\n                    })\n                        .then(function () { return _this._handleLoadingState(false); })\n                        .then(function () { return _this; });\n                }\n                // function returned something else than promise, let's check if it's an array of choices\n                if (!Array.isArray(fetcher_1)) {\n                    throw new TypeError(\".setChoices first argument function must return either array of choices or Promise, got: \".concat(typeof fetcher_1));\n                }\n                // recursion with results, it's sync and choices were cleared already\n                return this.setChoices(fetcher_1, value, label, false);\n            }\n            if (!Array.isArray(choicesArrayOrFetcher)) {\n                throw new TypeError(\".setChoices must be called either with array of choices with a function resulting into Promise of array of choices\");\n            }\n            this.containerOuter.removeLoadingState();\n            this._store.withTxn(function () {\n                if (clearSearchFlag) {\n                    _this._isSearching = false;\n                }\n                // Clear choices if needed\n                if (replaceChoices) {\n                    _this.clearChoices(true, replaceItems);\n                }\n                var isDefaultValue = value === 'value';\n                var isDefaultLabel = label === 'label';\n                choicesArrayOrFetcher.forEach(function (groupOrChoice) {\n                    if ('choices' in groupOrChoice) {\n                        var group = groupOrChoice;\n                        if (!isDefaultLabel) {\n                            group = __assign(__assign({}, group), { label: group[label] });\n                        }\n                        _this._addGroup(mapInputToChoice(group, true));\n                    }\n                    else {\n                        var choice = groupOrChoice;\n                        if (!isDefaultLabel || !isDefaultValue) {\n                            choice = __assign(__assign({}, choice), { value: choice[value], label: choice[label] });\n                        }\n                        var choiceFull = mapInputToChoice(choice, false);\n                        _this._addChoice(choiceFull);\n                        if (choiceFull.placeholder && !_this._hasNonChoicePlaceholder) {\n                            _this._placeholderValue = unwrapStringForEscaped(choiceFull.label);\n                        }\n                    }\n                });\n                _this.unhighlightAll();\n            });\n            // @todo integrate with Store\n            this._searcher.reset();\n            return this;\n        };\n        Choices.prototype.refresh = function (withEvents, selectFirstOption, deselectAll) {\n            var _this = this;\n            if (withEvents === void 0) { withEvents = false; }\n            if (selectFirstOption === void 0) { selectFirstOption = false; }\n            if (deselectAll === void 0) { deselectAll = false; }\n            if (!this._isSelectElement) {\n                if (!this.config.silent) {\n                    console.warn('refresh method can only be used on choices backed by a <select> element');\n                }\n                return this;\n            }\n            this._store.withTxn(function () {\n                var choicesFromOptions = _this.passedElement.optionsAsChoices();\n                // Build the list of items which require preserving\n                var existingItems = {};\n                if (!deselectAll) {\n                    _this._store.items.forEach(function (choice) {\n                        if (choice.id && choice.active && choice.selected) {\n                            existingItems[choice.value] = true;\n                        }\n                    });\n                }\n                _this.clearStore(false);\n                var updateChoice = function (choice) {\n                    if (deselectAll) {\n                        _this._store.dispatch(removeItem$1(choice));\n                    }\n                    else if (existingItems[choice.value]) {\n                        choice.selected = true;\n                    }\n                };\n                choicesFromOptions.forEach(function (groupOrChoice) {\n                    if ('choices' in groupOrChoice) {\n                        groupOrChoice.choices.forEach(updateChoice);\n                        return;\n                    }\n                    updateChoice(groupOrChoice);\n                });\n                /* @todo only generate add events for the added options instead of all\n                if (withEvents) {\n                  items.forEach((choice) => {\n                    if (existingItems[choice.value]) {\n                      this.passedElement.triggerEvent(\n                        EventType.removeItem,\n                        this._getChoiceForEvent(choice),\n                      );\n                    }\n                  });\n                }\n                */\n                // load new choices & items\n                _this._addPredefinedChoices(choicesFromOptions, selectFirstOption, withEvents);\n                // re-do search if required\n                if (_this._isSearching) {\n                    _this._searchChoices(_this.input.value);\n                }\n            });\n            return this;\n        };\n        Choices.prototype.removeChoice = function (value) {\n            var choice = this._store.choices.find(function (c) { return c.value === value; });\n            if (!choice) {\n                return this;\n            }\n            this._clearNotice();\n            this._store.dispatch(removeChoice(choice));\n            // @todo integrate with Store\n            this._searcher.reset();\n            if (choice.selected) {\n                this.passedElement.triggerEvent(EventType.removeItem, getChoiceForOutput(choice));\n            }\n            return this;\n        };\n        Choices.prototype.clearChoices = function (clearOptions, clearItems) {\n            var _this = this;\n            if (clearOptions === void 0) { clearOptions = true; }\n            if (clearItems === void 0) { clearItems = false; }\n            if (clearOptions) {\n                if (clearItems) {\n                    this.passedElement.element.replaceChildren('');\n                }\n                else {\n                    this.passedElement.element.querySelectorAll(':not([selected])').forEach(function (el) {\n                        el.remove();\n                    });\n                }\n            }\n            this.itemList.element.replaceChildren('');\n            this.choiceList.element.replaceChildren('');\n            this._clearNotice();\n            this._store.withTxn(function () {\n                var items = clearItems ? [] : _this._store.items;\n                _this._store.reset();\n                items.forEach(function (item) {\n                    _this._store.dispatch(addChoice(item));\n                    _this._store.dispatch(addItem(item));\n                });\n            });\n            // @todo integrate with Store\n            this._searcher.reset();\n            return this;\n        };\n        Choices.prototype.clearStore = function (clearOptions) {\n            if (clearOptions === void 0) { clearOptions = true; }\n            this.clearChoices(clearOptions, true);\n            this._stopSearch();\n            this._lastAddedChoiceId = 0;\n            this._lastAddedGroupId = 0;\n            return this;\n        };\n        Choices.prototype.clearInput = function () {\n            var shouldSetInputWidth = !this._isSelectOneElement;\n            this.input.clear(shouldSetInputWidth);\n            this._stopSearch();\n            return this;\n        };\n        Choices.prototype._validateConfig = function () {\n            var config = this.config;\n            var invalidConfigOptions = diff(config, DEFAULT_CONFIG);\n            if (invalidConfigOptions.length) {\n                console.warn('Unknown config option(s) passed', invalidConfigOptions.join(', '));\n            }\n            if (config.allowHTML && config.allowHtmlUserInput) {\n                if (config.addItems) {\n                    console.warn('Warning: allowHTML/allowHtmlUserInput/addItems all being true is strongly not recommended and may lead to XSS attacks');\n                }\n                if (config.addChoices) {\n                    console.warn('Warning: allowHTML/allowHtmlUserInput/addChoices all being true is strongly not recommended and may lead to XSS attacks');\n                }\n            }\n        };\n        Choices.prototype._render = function (changes) {\n            if (changes === void 0) { changes = { choices: true, groups: true, items: true }; }\n            if (this._store.inTxn()) {\n                return;\n            }\n            if (this._isSelectElement) {\n                if (changes.choices || changes.groups) {\n                    this._renderChoices();\n                }\n            }\n            if (changes.items) {\n                this._renderItems();\n            }\n        };\n        Choices.prototype._renderChoices = function () {\n            var _this = this;\n            if (!this._canAddItems()) {\n                return; // block rendering choices if the input limit is reached.\n            }\n            var _a = this, config = _a.config, isSearching = _a._isSearching;\n            var _b = this._store, activeGroups = _b.activeGroups, activeChoices = _b.activeChoices;\n            var renderLimit = isSearching ? config.searchResultLimit : config.renderChoiceLimit;\n            if (this._isSelectElement) {\n                var backingOptions = activeChoices.filter(function (choice) { return !choice.element; });\n                if (backingOptions.length) {\n                    this.passedElement.addOptions(backingOptions);\n                }\n            }\n            var fragment = document.createDocumentFragment();\n            var renderableChoices = function (choices) {\n                return choices.filter(function (choice) {\n                    return !choice.placeholder &&\n                        (isSearching\n                            ? (config.searchRenderSelectedChoices || !choice.selected) && !!choice.rank\n                            : config.renderSelectedChoices || !choice.selected);\n                });\n            };\n            var showLabel = config.appendGroupInSearch && isSearching;\n            var selectableChoices = false;\n            var highlightedEl = null;\n            var renderChoices = function (choices, withinGroup) {\n                if (isSearching) {\n                    // sortByRank is used to ensure stable sorting, as scores are non-unique\n                    // this additionally ensures fuseOptions.sortFn is not ignored\n                    choices.sort(sortByRank);\n                }\n                else if (config.shouldSort) {\n                    choices.sort(config.sorter);\n                }\n                var choiceLimit = choices.length;\n                choiceLimit = !withinGroup && renderLimit > 0 && choiceLimit > renderLimit ? renderLimit : choiceLimit;\n                choiceLimit--;\n                choices.every(function (choice, index) {\n                    // choiceEl being empty signals the contents has probably significantly changed\n                    var dropdownItem = choice.choiceEl ||\n                        _this._templates.choice(config, choice, config.itemSelectText, showLabel && choice.group ? choice.group.label : undefined);\n                    choice.choiceEl = dropdownItem;\n                    fragment.appendChild(dropdownItem);\n                    if (isSearching || !choice.selected) {\n                        selectableChoices = true;\n                    }\n                    else if (!highlightedEl) {\n                        highlightedEl = dropdownItem;\n                    }\n                    return index < choiceLimit;\n                });\n            };\n            if (activeChoices.length) {\n                if (config.resetScrollPosition) {\n                    requestAnimationFrame(function () { return _this.choiceList.scrollToTop(); });\n                }\n                if (!this._hasNonChoicePlaceholder && !isSearching && this._isSelectOneElement) {\n                    // If we have a placeholder choice along with groups\n                    renderChoices(activeChoices.filter(function (choice) { return choice.placeholder && !choice.group; }), false);\n                }\n                // If we have grouped options\n                if (activeGroups.length && !isSearching) {\n                    if (config.shouldSort) {\n                        activeGroups.sort(config.sorter);\n                    }\n                    // render Choices without group first, regardless of sort, otherwise they won't be distinguishable\n                    // from the last group\n                    renderChoices(activeChoices.filter(function (choice) { return !choice.placeholder && !choice.group; }), false);\n                    activeGroups.forEach(function (group) {\n                        var groupChoices = renderableChoices(group.choices);\n                        if (groupChoices.length) {\n                            if (group.label) {\n                                var dropdownGroup = group.groupEl || _this._templates.choiceGroup(_this.config, group);\n                                group.groupEl = dropdownGroup;\n                                dropdownGroup.remove();\n                                fragment.appendChild(dropdownGroup);\n                            }\n                            renderChoices(groupChoices, true);\n                        }\n                    });\n                }\n                else {\n                    renderChoices(renderableChoices(activeChoices), false);\n                }\n            }\n            if (!selectableChoices && (isSearching || !fragment.children.length || !config.renderSelectedChoices)) {\n                if (!this._notice) {\n                    this._notice = {\n                        text: resolveStringFunction(isSearching ? config.noResultsText : config.noChoicesText),\n                        type: isSearching ? NoticeTypes.noResults : NoticeTypes.noChoices,\n                    };\n                }\n                fragment.replaceChildren('');\n            }\n            this._renderNotice(fragment);\n            this.choiceList.element.replaceChildren(fragment);\n            this._highlightChoice(highlightedEl);\n        };\n        Choices.prototype._renderItems = function () {\n            var _this = this;\n            var items = this._store.items || [];\n            var itemList = this.itemList.element;\n            var config = this.config;\n            var fragment = document.createDocumentFragment();\n            var itemFromList = function (item) {\n                return itemList.querySelector(\"[data-item][data-id=\\\"\".concat(item.id, \"\\\"]\"));\n            };\n            var addItemToFragment = function (item) {\n                var el = item.itemEl;\n                if (el && el.parentElement) {\n                    return;\n                }\n                el = itemFromList(item) || _this._templates.item(config, item, config.removeItemButton);\n                item.itemEl = el;\n                fragment.appendChild(el);\n            };\n            // new items\n            items.forEach(addItemToFragment);\n            var addedItems = !!fragment.childNodes.length;\n            if (this._isSelectOneElement) {\n                var existingItems = itemList.children.length;\n                if (addedItems || existingItems > 1) {\n                    var placeholder = itemList.querySelector(getClassNamesSelector(config.classNames.placeholder));\n                    if (placeholder) {\n                        placeholder.remove();\n                    }\n                }\n                else if (!addedItems && !existingItems && this._placeholderValue) {\n                    addedItems = true;\n                    addItemToFragment(mapInputToChoice({\n                        selected: true,\n                        value: '',\n                        label: this._placeholderValue,\n                        placeholder: true,\n                    }, false));\n                }\n            }\n            if (addedItems) {\n                itemList.append(fragment);\n                if (config.shouldSortItems && !this._isSelectOneElement) {\n                    items.sort(config.sorter);\n                    // push sorting into the DOM\n                    items.forEach(function (item) {\n                        var el = itemFromList(item);\n                        if (el) {\n                            el.remove();\n                            fragment.append(el);\n                        }\n                    });\n                    itemList.append(fragment);\n                }\n            }\n            if (this._isTextElement) {\n                // Update the value of the hidden input\n                this.passedElement.value = items.map(function (_a) {\n                    var value = _a.value;\n                    return value;\n                }).join(config.delimiter);\n            }\n        };\n        Choices.prototype._displayNotice = function (text, type, openDropdown) {\n            if (openDropdown === void 0) { openDropdown = true; }\n            var oldNotice = this._notice;\n            if (oldNotice &&\n                ((oldNotice.type === type && oldNotice.text === text) ||\n                    (oldNotice.type === NoticeTypes.addChoice &&\n                        (type === NoticeTypes.noResults || type === NoticeTypes.noChoices)))) {\n                if (openDropdown) {\n                    this.showDropdown(true);\n                }\n                return;\n            }\n            this._clearNotice();\n            this._notice = text\n                ? {\n                    text: text,\n                    type: type,\n                }\n                : undefined;\n            this._renderNotice();\n            if (openDropdown && text) {\n                this.showDropdown(true);\n            }\n        };\n        Choices.prototype._clearNotice = function () {\n            if (!this._notice) {\n                return;\n            }\n            var noticeElement = this.choiceList.element.querySelector(getClassNamesSelector(this.config.classNames.notice));\n            if (noticeElement) {\n                noticeElement.remove();\n            }\n            this._notice = undefined;\n        };\n        Choices.prototype._renderNotice = function (fragment) {\n            var noticeConf = this._notice;\n            if (noticeConf) {\n                var notice = this._templates.notice(this.config, noticeConf.text, noticeConf.type);\n                if (fragment) {\n                    fragment.append(notice);\n                }\n                else {\n                    this.choiceList.prepend(notice);\n                }\n            }\n        };\n        /**\n         * @deprecated Use utils.getChoiceForOutput\n         */\n        // eslint-disable-next-line class-methods-use-this\n        Choices.prototype._getChoiceForOutput = function (choice, keyCode) {\n            return getChoiceForOutput(choice, keyCode);\n        };\n        Choices.prototype._triggerChange = function (value) {\n            if (value === undefined || value === null) {\n                return;\n            }\n            this.passedElement.triggerEvent(EventType.change, {\n                value: value,\n            });\n        };\n        Choices.prototype._handleButtonAction = function (element) {\n            var _this = this;\n            var items = this._store.items;\n            if (!items.length || !this.config.removeItems || !this.config.removeItemButton) {\n                return;\n            }\n            var id = element && parseDataSetId(element.closest('[data-id]'));\n            var itemToRemove = id && items.find(function (item) { return item.id === id; });\n            if (!itemToRemove) {\n                return;\n            }\n            this._store.withTxn(function () {\n                // Remove item associated with button\n                _this._removeItem(itemToRemove);\n                _this._triggerChange(itemToRemove.value);\n                if (_this._isSelectOneElement && !_this._hasNonChoicePlaceholder) {\n                    var placeholderChoice = (_this.config.shouldSort ? _this._store.choices.reverse() : _this._store.choices).find(function (choice) { return choice.placeholder; });\n                    if (placeholderChoice) {\n                        _this._addItem(placeholderChoice);\n                        _this.unhighlightAll();\n                        if (placeholderChoice.value) {\n                            _this._triggerChange(placeholderChoice.value);\n                        }\n                    }\n                }\n            });\n        };\n        Choices.prototype._handleItemAction = function (element, hasShiftKey) {\n            var _this = this;\n            if (hasShiftKey === void 0) { hasShiftKey = false; }\n            var items = this._store.items;\n            if (!items.length || !this.config.removeItems || this._isSelectOneElement) {\n                return;\n            }\n            var id = parseDataSetId(element);\n            if (!id) {\n                return;\n            }\n            // We only want to select one item with a click\n            // so we deselect any items that aren't the target\n            // unless shift is being pressed\n            items.forEach(function (item) {\n                if (item.id === id && !item.highlighted) {\n                    _this.highlightItem(item);\n                }\n                else if (!hasShiftKey && item.highlighted) {\n                    _this.unhighlightItem(item);\n                }\n            });\n            // Focus input as without focus, a user cannot do anything with a\n            // highlighted item\n            this.input.focus();\n        };\n        Choices.prototype._handleChoiceAction = function (element) {\n            var _this = this;\n            // If we are clicking on an option\n            var id = parseDataSetId(element);\n            var choice = id && this._store.getChoiceById(id);\n            if (!choice || choice.disabled) {\n                return false;\n            }\n            var hasActiveDropdown = this.dropdown.isActive;\n            if (!choice.selected) {\n                if (!this._canAddItems()) {\n                    return true; // causes _onEnterKey to early out\n                }\n                this._store.withTxn(function () {\n                    _this._addItem(choice, true, true);\n                    _this.clearInput();\n                    _this.unhighlightAll();\n                });\n                this._triggerChange(choice.value);\n            }\n            // We want to close the dropdown if we are dealing with a single select box\n            if (hasActiveDropdown && this.config.closeDropdownOnSelect) {\n                this.hideDropdown(true);\n                this.containerOuter.element.focus();\n            }\n            return true;\n        };\n        Choices.prototype._handleBackspace = function (items) {\n            var config = this.config;\n            if (!config.removeItems || !items.length) {\n                return;\n            }\n            var lastItem = items[items.length - 1];\n            var hasHighlightedItems = items.some(function (item) { return item.highlighted; });\n            // If editing the last item is allowed and there are not other selected items,\n            // we can edit the item value. Otherwise if we can remove items, remove all selected items\n            if (config.editItems && !hasHighlightedItems && lastItem) {\n                this.input.value = lastItem.value;\n                this.input.setWidth();\n                this._removeItem(lastItem);\n                this._triggerChange(lastItem.value);\n            }\n            else {\n                if (!hasHighlightedItems) {\n                    // Highlight last item if none already highlighted\n                    this.highlightItem(lastItem, false);\n                }\n                this.removeHighlightedItems(true);\n            }\n        };\n        Choices.prototype._loadChoices = function () {\n            var _a;\n            var _this = this;\n            var config = this.config;\n            if (this._isTextElement) {\n                // Assign preset items from passed object first\n                this._presetChoices = config.items.map(function (e) { return mapInputToChoice(e, false); });\n                // Add any values passed from attribute\n                if (this.passedElement.value) {\n                    var elementItems = this.passedElement.value\n                        .split(config.delimiter)\n                        .map(function (e) { return mapInputToChoice(e, false, _this.config.allowHtmlUserInput); });\n                    this._presetChoices = this._presetChoices.concat(elementItems);\n                }\n                this._presetChoices.forEach(function (choice) {\n                    choice.selected = true;\n                });\n            }\n            else if (this._isSelectElement) {\n                // Assign preset choices from passed object\n                this._presetChoices = config.choices.map(function (e) { return mapInputToChoice(e, true); });\n                // Create array of choices from option elements\n                var choicesFromOptions = this.passedElement.optionsAsChoices();\n                if (choicesFromOptions) {\n                    (_a = this._presetChoices).push.apply(_a, choicesFromOptions);\n                }\n            }\n        };\n        Choices.prototype._handleLoadingState = function (setLoading) {\n            if (setLoading === void 0) { setLoading = true; }\n            var el = this.itemList.element;\n            if (setLoading) {\n                this.disable();\n                this.containerOuter.addLoadingState();\n                if (this._isSelectOneElement) {\n                    el.replaceChildren(this._templates.placeholder(this.config, this.config.loadingText));\n                }\n                else {\n                    this.input.placeholder = this.config.loadingText;\n                }\n            }\n            else {\n                this.enable();\n                this.containerOuter.removeLoadingState();\n                if (this._isSelectOneElement) {\n                    el.replaceChildren('');\n                    this._render();\n                }\n                else {\n                    this.input.placeholder = this._placeholderValue || '';\n                }\n            }\n        };\n        Choices.prototype._handleSearch = function (value) {\n            if (!this.input.isFocussed) {\n                return;\n            }\n            // Check that we have a value to search and the input was an alphanumeric character\n            if (value !== null && typeof value !== 'undefined' && value.length >= this.config.searchFloor) {\n                var resultCount = this.config.searchChoices ? this._searchChoices(value) : 0;\n                if (resultCount !== null) {\n                    // Trigger search event\n                    this.passedElement.triggerEvent(EventType.search, {\n                        value: value,\n                        resultCount: resultCount,\n                    });\n                }\n            }\n            else if (this._store.choices.some(function (option) { return !option.active; })) {\n                this._stopSearch();\n            }\n        };\n        Choices.prototype._canAddItems = function () {\n            var config = this.config;\n            var maxItemCount = config.maxItemCount, maxItemText = config.maxItemText;\n            if (!config.singleModeForMultiSelect && maxItemCount > 0 && maxItemCount <= this._store.items.length) {\n                this.choiceList.element.replaceChildren('');\n                this._notice = undefined;\n                this._displayNotice(typeof maxItemText === 'function' ? maxItemText(maxItemCount) : maxItemText, NoticeTypes.addChoice);\n                return false;\n            }\n            if (this._notice && this._notice.type === NoticeTypes.addChoice) {\n                this._clearNotice();\n            }\n            return true;\n        };\n        Choices.prototype._canCreateItem = function (value) {\n            var config = this.config;\n            var canAddItem = true;\n            var notice = '';\n            if (canAddItem && typeof config.addItemFilter === 'function' && !config.addItemFilter(value)) {\n                canAddItem = false;\n                notice = resolveNoticeFunction(config.customAddItemText, value, undefined);\n            }\n            if (canAddItem) {\n                var foundChoice = this._store.choices.find(function (choice) { return config.valueComparer(choice.value, value); });\n                if (foundChoice) {\n                    if (this._isSelectElement) {\n                        // for exact matches, do not prompt to add it as a custom choice\n                        this._displayNotice('', NoticeTypes.addChoice);\n                        return false;\n                    }\n                    if (!config.duplicateItemsAllowed) {\n                        canAddItem = false;\n                        notice = resolveNoticeFunction(config.uniqueItemText, value, undefined);\n                    }\n                }\n            }\n            if (canAddItem) {\n                notice = resolveNoticeFunction(config.addItemText, value, undefined);\n            }\n            if (notice) {\n                this._displayNotice(notice, NoticeTypes.addChoice);\n            }\n            return canAddItem;\n        };\n        Choices.prototype._searchChoices = function (value) {\n            var newValue = value.trim().replace(/\\s{2,}/, ' ');\n            // signal input didn't change search\n            if (!newValue.length || newValue === this._currentValue) {\n                return null;\n            }\n            var searcher = this._searcher;\n            if (searcher.isEmptyIndex()) {\n                searcher.index(this._store.searchableChoices);\n            }\n            // If new value matches the desired length and is not the same as the current value with a space\n            var results = searcher.search(newValue);\n            this._currentValue = newValue;\n            this._highlightPosition = 0;\n            this._isSearching = true;\n            var notice = this._notice;\n            var noticeType = notice && notice.type;\n            if (noticeType !== NoticeTypes.addChoice) {\n                if (!results.length) {\n                    this._displayNotice(resolveStringFunction(this.config.noResultsText), NoticeTypes.noResults);\n                }\n                else {\n                    this._clearNotice();\n                }\n            }\n            this._store.dispatch(filterChoices(results));\n            return results.length;\n        };\n        Choices.prototype._stopSearch = function () {\n            if (this._isSearching) {\n                this._currentValue = '';\n                this._isSearching = false;\n                this._clearNotice();\n                this._store.dispatch(activateChoices(true));\n                this.passedElement.triggerEvent(EventType.search, {\n                    value: '',\n                    resultCount: 0,\n                });\n            }\n        };\n        Choices.prototype._addEventListeners = function () {\n            var documentElement = this._docRoot;\n            var outerElement = this.containerOuter.element;\n            var inputElement = this.input.element;\n            var passedElement = this.passedElement.element;\n            // capture events - can cancel event processing or propagation\n            documentElement.addEventListener('touchend', this._onTouchEnd, true);\n            outerElement.addEventListener('keydown', this._onKeyDown, true);\n            outerElement.addEventListener('mousedown', this._onMouseDown, true);\n            // passive events - doesn't call `preventDefault` or `stopPropagation`\n            documentElement.addEventListener('click', this._onClick, { passive: true });\n            documentElement.addEventListener('touchmove', this._onTouchMove, {\n                passive: true,\n            });\n            this.dropdown.element.addEventListener('mouseover', this._onMouseOver, {\n                passive: true,\n            });\n            if (this._isSelectOneElement) {\n                outerElement.addEventListener('focus', this._onFocus, {\n                    passive: true,\n                });\n                outerElement.addEventListener('blur', this._onBlur, {\n                    passive: true,\n                });\n            }\n            inputElement.addEventListener('keyup', this._onKeyUp, {\n                passive: true,\n            });\n            inputElement.addEventListener('input', this._onInput, {\n                passive: true,\n            });\n            inputElement.addEventListener('focus', this._onFocus, {\n                passive: true,\n            });\n            inputElement.addEventListener('blur', this._onBlur, {\n                passive: true,\n            });\n            if (inputElement.form) {\n                inputElement.form.addEventListener('reset', this._onFormReset, {\n                    passive: true,\n                });\n            }\n            if (passedElement.hasAttribute('required')) {\n                passedElement.addEventListener('change', this._onChange, {\n                    passive: true,\n                });\n                passedElement.addEventListener('invalid', this._onInvalid, {\n                    passive: true,\n                });\n            }\n            this.input.addEventListeners();\n        };\n        Choices.prototype._removeEventListeners = function () {\n            var documentElement = this._docRoot;\n            var outerElement = this.containerOuter.element;\n            var inputElement = this.input.element;\n            var passedElement = this.passedElement.element;\n            documentElement.removeEventListener('touchend', this._onTouchEnd, true);\n            outerElement.removeEventListener('keydown', this._onKeyDown, true);\n            outerElement.removeEventListener('mousedown', this._onMouseDown, true);\n            documentElement.removeEventListener('click', this._onClick);\n            documentElement.removeEventListener('touchmove', this._onTouchMove);\n            this.dropdown.element.removeEventListener('mouseover', this._onMouseOver);\n            if (this._isSelectOneElement) {\n                outerElement.removeEventListener('focus', this._onFocus);\n                outerElement.removeEventListener('blur', this._onBlur);\n            }\n            inputElement.removeEventListener('keyup', this._onKeyUp);\n            inputElement.removeEventListener('input', this._onInput);\n            inputElement.removeEventListener('focus', this._onFocus);\n            inputElement.removeEventListener('blur', this._onBlur);\n            if (inputElement.form) {\n                inputElement.form.removeEventListener('reset', this._onFormReset);\n            }\n            if (passedElement.hasAttribute('required')) {\n                passedElement.removeEventListener('change', this._onChange);\n                passedElement.removeEventListener('invalid', this._onInvalid);\n            }\n            this.input.removeEventListeners();\n        };\n        Choices.prototype._onKeyDown = function (event) {\n            var keyCode = event.keyCode;\n            var hasActiveDropdown = this.dropdown.isActive;\n            /*\n            See:\n            https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key\n            https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values\n            https://en.wikipedia.org/wiki/UTF-16#Code_points_from_U+010000_to_U+10FFFF - UTF-16 surrogate pairs\n            https://stackoverflow.com/a/70866532 - \"Unidentified\" for mobile\n            http://www.unicode.org/versions/Unicode5.2.0/ch16.pdf#G19635 - U+FFFF is reserved (Section 16.7)\n        \n            Logic: when a key event is sent, `event.key` represents its printable value _or_ one\n            of a large list of special values indicating meta keys/functionality. In addition,\n            key events for compose functionality contain a value of `Dead` when mid-composition.\n        \n            I can't quite verify it, but non-English IMEs may also be able to generate key codes\n            for code points in the surrogate-pair range, which could potentially be seen as having\n            key.length > 1. Since `Fn` is one of the special keys, we can't distinguish by that\n            alone.\n        \n            Here, key.length === 1 means we know for sure the input was printable and not a special\n            `key` value. When the length is greater than 1, it could be either a printable surrogate\n            pair or a special `key` value. We can tell the difference by checking if the _character\n            code_ value (not code point!) is in the \"surrogate pair\" range or not.\n        \n            We don't use .codePointAt because an invalid code point would return 65535, which wouldn't\n            pass the >= 0x10000 check we would otherwise use.\n        \n            > ...The Unicode Standard sets aside 66 noncharacter code points. The last two code points\n            > of each plane are noncharacters: U+FFFE and U+FFFF on the BMP...\n            */\n            var wasPrintableChar = event.key.length === 1 ||\n                (event.key.length === 2 && event.key.charCodeAt(0) >= 0xd800) ||\n                event.key === 'Unidentified';\n            /*\n              We do not show the dropdown if focusing out with esc or navigating through input fields.\n              An activated search can still be opened with any other key.\n             */\n            if (!this._isTextElement &&\n                !hasActiveDropdown &&\n                keyCode !== KeyCodeMap.ESC_KEY &&\n                keyCode !== KeyCodeMap.TAB_KEY &&\n                keyCode !== KeyCodeMap.SHIFT_KEY) {\n                this.showDropdown();\n                if (!this.input.isFocussed && wasPrintableChar) {\n                    /*\n                      We update the input value with the pressed key as\n                      the input was not focussed at the time of key press\n                      therefore does not have the value of the key.\n                    */\n                    this.input.value += event.key;\n                    // browsers interpret a space as pagedown\n                    if (event.key === ' ') {\n                        event.preventDefault();\n                    }\n                }\n            }\n            switch (keyCode) {\n                case KeyCodeMap.A_KEY:\n                    return this._onSelectKey(event, this.itemList.element.hasChildNodes());\n                case KeyCodeMap.ENTER_KEY:\n                    return this._onEnterKey(event, hasActiveDropdown);\n                case KeyCodeMap.ESC_KEY:\n                    return this._onEscapeKey(event, hasActiveDropdown);\n                case KeyCodeMap.UP_KEY:\n                case KeyCodeMap.PAGE_UP_KEY:\n                case KeyCodeMap.DOWN_KEY:\n                case KeyCodeMap.PAGE_DOWN_KEY:\n                    return this._onDirectionKey(event, hasActiveDropdown);\n                case KeyCodeMap.DELETE_KEY:\n                case KeyCodeMap.BACK_KEY:\n                    return this._onDeleteKey(event, this._store.items, this.input.isFocussed);\n            }\n        };\n        Choices.prototype._onKeyUp = function ( /* event: KeyboardEvent */) {\n            this._canSearch = this.config.searchEnabled;\n        };\n        Choices.prototype._onInput = function ( /* event: InputEvent */) {\n            var value = this.input.value;\n            if (!value) {\n                if (this._isTextElement) {\n                    this.hideDropdown(true);\n                }\n                else {\n                    this._stopSearch();\n                }\n                return;\n            }\n            if (!this._canAddItems()) {\n                return;\n            }\n            if (this._canSearch) {\n                // do the search even if the entered text can not be added\n                this._handleSearch(value);\n            }\n            if (!this._canAddUserChoices) {\n                return;\n            }\n            // determine if a notice needs to be displayed for why a search result can't be added\n            this._canCreateItem(value);\n            if (this._isSelectElement) {\n                this._highlightPosition = 0; // reset to select the notice and/or exact match\n                this._highlightChoice();\n            }\n        };\n        Choices.prototype._onSelectKey = function (event, hasItems) {\n            // If CTRL + A or CMD + A have been pressed and there are items to select\n            if ((event.ctrlKey || event.metaKey) && hasItems) {\n                this._canSearch = false;\n                var shouldHightlightAll = this.config.removeItems && !this.input.value && this.input.element === document.activeElement;\n                if (shouldHightlightAll) {\n                    this.highlightAll();\n                }\n            }\n        };\n        Choices.prototype._onEnterKey = function (event, hasActiveDropdown) {\n            var _this = this;\n            var value = this.input.value;\n            var target = event.target;\n            event.preventDefault();\n            if (target && target.hasAttribute('data-button')) {\n                this._handleButtonAction(target);\n                return;\n            }\n            if (!hasActiveDropdown) {\n                if (this._isSelectElement || this._notice) {\n                    this.showDropdown();\n                }\n                return;\n            }\n            var highlightedChoice = this.dropdown.element.querySelector(getClassNamesSelector(this.config.classNames.highlightedState));\n            if (highlightedChoice && this._handleChoiceAction(highlightedChoice)) {\n                return;\n            }\n            if (!target || !value) {\n                this.hideDropdown(true);\n                return;\n            }\n            if (!this._canAddItems()) {\n                return;\n            }\n            var addedItem = false;\n            this._store.withTxn(function () {\n                addedItem = _this._findAndSelectChoiceByValue(value, true);\n                if (!addedItem) {\n                    if (!_this._canAddUserChoices) {\n                        return;\n                    }\n                    if (!_this._canCreateItem(value)) {\n                        return;\n                    }\n                    _this._addChoice(mapInputToChoice(value, false, _this.config.allowHtmlUserInput), true, true);\n                    addedItem = true;\n                }\n                _this.clearInput();\n                _this.unhighlightAll();\n            });\n            if (!addedItem) {\n                return;\n            }\n            this._triggerChange(value);\n            if (this.config.closeDropdownOnSelect) {\n                this.hideDropdown(true);\n            }\n        };\n        Choices.prototype._onEscapeKey = function (event, hasActiveDropdown) {\n            if (hasActiveDropdown) {\n                event.stopPropagation();\n                this.hideDropdown(true);\n                this._stopSearch();\n                this.containerOuter.element.focus();\n            }\n        };\n        Choices.prototype._onDirectionKey = function (event, hasActiveDropdown) {\n            var keyCode = event.keyCode;\n            // If up or down key is pressed, traverse through options\n            if (hasActiveDropdown || this._isSelectOneElement) {\n                this.showDropdown();\n                this._canSearch = false;\n                var directionInt = keyCode === KeyCodeMap.DOWN_KEY || keyCode === KeyCodeMap.PAGE_DOWN_KEY ? 1 : -1;\n                var skipKey = event.metaKey || keyCode === KeyCodeMap.PAGE_DOWN_KEY || keyCode === KeyCodeMap.PAGE_UP_KEY;\n                var nextEl = void 0;\n                if (skipKey) {\n                    if (directionInt > 0) {\n                        nextEl = this.dropdown.element.querySelector(\"\".concat(selectableChoiceIdentifier, \":last-of-type\"));\n                    }\n                    else {\n                        nextEl = this.dropdown.element.querySelector(selectableChoiceIdentifier);\n                    }\n                }\n                else {\n                    var currentEl = this.dropdown.element.querySelector(getClassNamesSelector(this.config.classNames.highlightedState));\n                    if (currentEl) {\n                        nextEl = getAdjacentEl(currentEl, selectableChoiceIdentifier, directionInt);\n                    }\n                    else {\n                        nextEl = this.dropdown.element.querySelector(selectableChoiceIdentifier);\n                    }\n                }\n                if (nextEl) {\n                    // We prevent default to stop the cursor moving\n                    // when pressing the arrow\n                    if (!isScrolledIntoView(nextEl, this.choiceList.element, directionInt)) {\n                        this.choiceList.scrollToChildElement(nextEl, directionInt);\n                    }\n                    this._highlightChoice(nextEl);\n                }\n                // Prevent default to maintain cursor position whilst\n                // traversing dropdown options\n                event.preventDefault();\n            }\n        };\n        Choices.prototype._onDeleteKey = function (event, items, hasFocusedInput) {\n            // If backspace or delete key is pressed and the input has no value\n            if (!this._isSelectOneElement && !event.target.value && hasFocusedInput) {\n                this._handleBackspace(items);\n                event.preventDefault();\n            }\n        };\n        Choices.prototype._onTouchMove = function () {\n            if (this._wasTap) {\n                this._wasTap = false;\n            }\n        };\n        Choices.prototype._onTouchEnd = function (event) {\n            var target = (event || event.touches[0]).target;\n            var touchWasWithinContainer = this._wasTap && this.containerOuter.element.contains(target);\n            if (touchWasWithinContainer) {\n                var containerWasExactTarget = target === this.containerOuter.element || target === this.containerInner.element;\n                if (containerWasExactTarget) {\n                    if (this._isTextElement) {\n                        this.input.focus();\n                    }\n                    else if (this._isSelectMultipleElement) {\n                        this.showDropdown();\n                    }\n                }\n                // Prevents focus event firing\n                event.stopPropagation();\n            }\n            this._wasTap = true;\n        };\n        /**\n         * Handles mousedown event in capture mode for containetOuter.element\n         */\n        Choices.prototype._onMouseDown = function (event) {\n            var target = event.target;\n            if (!(target instanceof Element)) {\n                return;\n            }\n            // If we have our mouse down on the scrollbar and are on IE11...\n            if (IS_IE11 && this.choiceList.element.contains(target)) {\n                // check if click was on a scrollbar area\n                var firstChoice = this.choiceList.element.firstElementChild;\n                this._isScrollingOnIe =\n                    this._direction === 'ltr' ? event.offsetX >= firstChoice.offsetWidth : event.offsetX < firstChoice.offsetLeft;\n            }\n            if (target === this.input.element) {\n                return;\n            }\n            var item = target.closest('[data-button],[data-item],[data-choice]');\n            if (item instanceof HTMLElement) {\n                if ('button' in item.dataset) {\n                    this._handleButtonAction(item);\n                }\n                else if ('item' in item.dataset) {\n                    this._handleItemAction(item, event.shiftKey);\n                }\n                else if ('choice' in item.dataset) {\n                    this._handleChoiceAction(item);\n                }\n            }\n            event.preventDefault();\n        };\n        /**\n         * Handles mouseover event over this.dropdown\n         * @param {MouseEvent} event\n         */\n        Choices.prototype._onMouseOver = function (_a) {\n            var target = _a.target;\n            if (target instanceof HTMLElement && 'choice' in target.dataset) {\n                this._highlightChoice(target);\n            }\n        };\n        Choices.prototype._onClick = function (_a) {\n            var target = _a.target;\n            var containerOuter = this.containerOuter;\n            var clickWasWithinContainer = containerOuter.element.contains(target);\n            if (clickWasWithinContainer) {\n                if (!this.dropdown.isActive && !containerOuter.isDisabled) {\n                    if (this._isTextElement) {\n                        if (document.activeElement !== this.input.element) {\n                            this.input.focus();\n                        }\n                    }\n                    else {\n                        this.showDropdown();\n                        containerOuter.element.focus();\n                    }\n                }\n                else if (this._isSelectOneElement &&\n                    target !== this.input.element &&\n                    !this.dropdown.element.contains(target)) {\n                    this.hideDropdown();\n                }\n            }\n            else {\n                containerOuter.removeFocusState();\n                this.hideDropdown(true);\n                this.unhighlightAll();\n            }\n        };\n        Choices.prototype._onFocus = function (_a) {\n            var target = _a.target;\n            var containerOuter = this.containerOuter;\n            var focusWasWithinContainer = target && containerOuter.element.contains(target);\n            if (!focusWasWithinContainer) {\n                return;\n            }\n            var targetIsInput = target === this.input.element;\n            if (this._isTextElement) {\n                if (targetIsInput) {\n                    containerOuter.addFocusState();\n                }\n            }\n            else if (this._isSelectMultipleElement) {\n                if (targetIsInput) {\n                    this.showDropdown(true);\n                    // If element is a select box, the focused element is the container and the dropdown\n                    // isn't already open, focus and show dropdown\n                    containerOuter.addFocusState();\n                }\n            }\n            else {\n                containerOuter.addFocusState();\n                if (targetIsInput) {\n                    this.showDropdown(true);\n                }\n            }\n        };\n        Choices.prototype._onBlur = function (_a) {\n            var target = _a.target;\n            var containerOuter = this.containerOuter;\n            var blurWasWithinContainer = target && containerOuter.element.contains(target);\n            if (blurWasWithinContainer && !this._isScrollingOnIe) {\n                if (target === this.input.element) {\n                    containerOuter.removeFocusState();\n                    this.hideDropdown(true);\n                    if (this._isTextElement || this._isSelectMultipleElement) {\n                        this.unhighlightAll();\n                    }\n                }\n                else if (target === this.containerOuter.element) {\n                    // Remove the focus state when the past outerContainer was the target\n                    containerOuter.removeFocusState();\n                    // Also close the dropdown if search is disabled\n                    if (!this.config.searchEnabled) {\n                        this.hideDropdown(true);\n                    }\n                }\n            }\n            else {\n                // On IE11, clicking the scollbar blurs our input and thus\n                // closes the dropdown. To stop this, we refocus our input\n                // if we know we are on IE *and* are scrolling.\n                this._isScrollingOnIe = false;\n                this.input.element.focus();\n            }\n        };\n        Choices.prototype._onFormReset = function () {\n            var _this = this;\n            this._store.withTxn(function () {\n                _this.clearInput();\n                _this.hideDropdown();\n                _this.refresh(false, false, true);\n                if (_this._initialItems.length) {\n                    _this.setChoiceByValue(_this._initialItems);\n                }\n            });\n        };\n        Choices.prototype._onChange = function (event) {\n            if (!event.target.checkValidity()) {\n                return;\n            }\n            this.containerOuter.removeInvalidState();\n        };\n        Choices.prototype._onInvalid = function () {\n            this.containerOuter.addInvalidState();\n        };\n        /**\n         * Removes any highlighted choice options\n         */\n        Choices.prototype._removeHighlightedChoices = function () {\n            var highlightedState = this.config.classNames.highlightedState;\n            var highlightedChoices = Array.from(this.dropdown.element.querySelectorAll(getClassNamesSelector(highlightedState)));\n            // Remove any highlighted choices\n            highlightedChoices.forEach(function (choice) {\n                removeClassesFromElement(choice, highlightedState);\n                choice.setAttribute('aria-selected', 'false');\n            });\n        };\n        Choices.prototype._highlightChoice = function (el) {\n            if (el === void 0) { el = null; }\n            var choices = Array.from(this.dropdown.element.querySelectorAll(selectableChoiceIdentifier));\n            if (!choices.length) {\n                return;\n            }\n            var passedEl = el;\n            var highlightedState = this.config.classNames.highlightedState;\n            this._removeHighlightedChoices();\n            if (passedEl) {\n                this._highlightPosition = choices.indexOf(passedEl);\n            }\n            else {\n                // Highlight choice based on last known highlight location\n                if (choices.length > this._highlightPosition) {\n                    // If we have an option to highlight\n                    passedEl = choices[this._highlightPosition];\n                }\n                else {\n                    // Otherwise highlight the option before\n                    passedEl = choices[choices.length - 1];\n                }\n                if (!passedEl) {\n                    passedEl = choices[0];\n                }\n            }\n            addClassesToElement(passedEl, highlightedState);\n            passedEl.setAttribute('aria-selected', 'true');\n            this.passedElement.triggerEvent(EventType.highlightChoice, {\n                el: passedEl,\n            });\n            if (this.dropdown.isActive) {\n                // IE11 ignores aria-label and blocks virtual keyboard\n                // if aria-activedescendant is set without a dropdown\n                this.input.setActiveDescendant(passedEl.id);\n                this.containerOuter.setActiveDescendant(passedEl.id);\n            }\n        };\n        Choices.prototype._addItem = function (item, withEvents, userTriggered) {\n            if (withEvents === void 0) { withEvents = true; }\n            if (userTriggered === void 0) { userTriggered = false; }\n            if (!item.id) {\n                throw new TypeError('item.id must be set before _addItem is called for a choice/item');\n            }\n            if (this.config.singleModeForMultiSelect || this._isSelectOneElement) {\n                this.removeActiveItems(item.id);\n            }\n            this._store.dispatch(addItem(item));\n            if (withEvents) {\n                var eventChoice = getChoiceForOutput(item);\n                this.passedElement.triggerEvent(EventType.addItem, eventChoice);\n                if (userTriggered) {\n                    this.passedElement.triggerEvent(EventType.choice, eventChoice);\n                }\n            }\n        };\n        Choices.prototype._removeItem = function (item) {\n            if (!item.id) {\n                return;\n            }\n            this._store.dispatch(removeItem$1(item));\n            var notice = this._notice;\n            if (notice && notice.type === NoticeTypes.noChoices) {\n                this._clearNotice();\n            }\n            this.passedElement.triggerEvent(EventType.removeItem, getChoiceForOutput(item));\n        };\n        Choices.prototype._addChoice = function (choice, withEvents, userTriggered) {\n            if (withEvents === void 0) { withEvents = true; }\n            if (userTriggered === void 0) { userTriggered = false; }\n            if (choice.id) {\n                throw new TypeError('Can not re-add a choice which has already been added');\n            }\n            var config = this.config;\n            if (!config.duplicateItemsAllowed && this._store.choices.find(function (c) { return config.valueComparer(c.value, choice.value); })) {\n                return;\n            }\n            // Generate unique id, in-place update is required so chaining _addItem works as expected\n            this._lastAddedChoiceId++;\n            choice.id = this._lastAddedChoiceId;\n            choice.elementId = \"\".concat(this._baseId, \"-\").concat(this._idNames.itemChoice, \"-\").concat(choice.id);\n            var prependValue = config.prependValue, appendValue = config.appendValue;\n            if (prependValue) {\n                choice.value = prependValue + choice.value;\n            }\n            if (appendValue) {\n                choice.value += appendValue.toString();\n            }\n            if ((prependValue || appendValue) && choice.element) {\n                choice.element.value = choice.value;\n            }\n            this._clearNotice();\n            this._store.dispatch(addChoice(choice));\n            if (choice.selected) {\n                this._addItem(choice, withEvents, userTriggered);\n            }\n        };\n        Choices.prototype._addGroup = function (group, withEvents) {\n            var _this = this;\n            if (withEvents === void 0) { withEvents = true; }\n            if (group.id) {\n                throw new TypeError('Can not re-add a group which has already been added');\n            }\n            this._store.dispatch(addGroup(group));\n            if (!group.choices) {\n                return;\n            }\n            // add unique id for the group(s), and do not store the full list of choices in this group\n            this._lastAddedGroupId++;\n            group.id = this._lastAddedGroupId;\n            group.choices.forEach(function (item) {\n                item.group = group;\n                if (group.disabled) {\n                    item.disabled = true;\n                }\n                _this._addChoice(item, withEvents);\n            });\n        };\n        Choices.prototype._createTemplates = function () {\n            var _this = this;\n            var callbackOnCreateTemplates = this.config.callbackOnCreateTemplates;\n            var userTemplates = {};\n            if (typeof callbackOnCreateTemplates === 'function') {\n                userTemplates = callbackOnCreateTemplates.call(this, strToEl, escapeForTemplate, getClassNames);\n            }\n            var templating = {};\n            Object.keys(this._templates).forEach(function (name) {\n                if (name in userTemplates) {\n                    templating[name] = userTemplates[name].bind(_this);\n                }\n                else {\n                    templating[name] = _this._templates[name].bind(_this);\n                }\n            });\n            this._templates = templating;\n        };\n        Choices.prototype._createElements = function () {\n            var templating = this._templates;\n            var _a = this, config = _a.config, isSelectOneElement = _a._isSelectOneElement;\n            var position = config.position, classNames = config.classNames;\n            var elementType = this._elementType;\n            this.containerOuter = new Container({\n                element: templating.containerOuter(config, this._direction, this._isSelectElement, isSelectOneElement, config.searchEnabled, elementType, config.labelId),\n                classNames: classNames,\n                type: elementType,\n                position: position,\n            });\n            this.containerInner = new Container({\n                element: templating.containerInner(config),\n                classNames: classNames,\n                type: elementType,\n                position: position,\n            });\n            this.input = new Input({\n                element: templating.input(config, this._placeholderValue),\n                classNames: classNames,\n                type: elementType,\n                preventPaste: !config.paste,\n            });\n            this.choiceList = new List({\n                element: templating.choiceList(config, isSelectOneElement),\n            });\n            this.itemList = new List({\n                element: templating.itemList(config, isSelectOneElement),\n            });\n            this.dropdown = new Dropdown({\n                element: templating.dropdown(config),\n                classNames: classNames,\n                type: elementType,\n            });\n        };\n        Choices.prototype._createStructure = function () {\n            var _a = this, containerInner = _a.containerInner, containerOuter = _a.containerOuter, passedElement = _a.passedElement;\n            var dropdownElement = this.dropdown.element;\n            // Hide original element\n            passedElement.conceal();\n            // Wrap input in container preserving DOM ordering\n            containerInner.wrap(passedElement.element);\n            // Wrapper inner container with outer container\n            containerOuter.wrap(containerInner.element);\n            containerOuter.element.appendChild(containerInner.element);\n            containerOuter.element.appendChild(dropdownElement);\n            containerInner.element.appendChild(this.itemList.element);\n            dropdownElement.appendChild(this.choiceList.element);\n            if (this._isSelectOneElement) {\n                this.input.placeholder = this.config.searchPlaceholderValue || '';\n                if (this.config.searchEnabled) {\n                    dropdownElement.insertBefore(this.input.element, dropdownElement.firstChild);\n                }\n            }\n            else {\n                if (!this._isSelectMultipleElement || this.config.searchEnabled) {\n                    containerInner.element.appendChild(this.input.element);\n                }\n                if (this._placeholderValue) {\n                    this.input.placeholder = this._placeholderValue;\n                }\n                this.input.setWidth();\n            }\n            this._highlightPosition = 0;\n            this._isSearching = false;\n        };\n        Choices.prototype._initStore = function () {\n            var _this = this;\n            this._store.subscribe(this._render).withTxn(function () {\n                _this._addPredefinedChoices(_this._presetChoices, _this._isSelectOneElement && !_this._hasNonChoicePlaceholder, false);\n            });\n            if (!this._store.choices.length || (this._isSelectOneElement && this._hasNonChoicePlaceholder)) {\n                this._render();\n            }\n        };\n        Choices.prototype._addPredefinedChoices = function (choices, selectFirstOption, withEvents) {\n            var _this = this;\n            if (selectFirstOption === void 0) { selectFirstOption = false; }\n            if (withEvents === void 0) { withEvents = true; }\n            if (selectFirstOption) {\n                /**\n                 * If there is a selected choice already or the choice is not the first in\n                 * the array, add each choice normally.\n                 *\n                 * Otherwise we pre-select the first enabled choice in the array (\"select-one\" only)\n                 */\n                var noSelectedChoices = choices.findIndex(function (choice) { return choice.selected; }) === -1;\n                if (noSelectedChoices) {\n                    choices.some(function (choice) {\n                        if (choice.disabled || 'choices' in choice) {\n                            return false;\n                        }\n                        choice.selected = true;\n                        return true;\n                    });\n                }\n            }\n            choices.forEach(function (item) {\n                if ('choices' in item) {\n                    if (_this._isSelectElement) {\n                        _this._addGroup(item, withEvents);\n                    }\n                }\n                else {\n                    _this._addChoice(item, withEvents);\n                }\n            });\n        };\n        Choices.prototype._findAndSelectChoiceByValue = function (value, userTriggered) {\n            var _this = this;\n            if (userTriggered === void 0) { userTriggered = false; }\n            // Check 'value' property exists and the choice isn't already selected\n            var foundChoice = this._store.choices.find(function (choice) { return _this.config.valueComparer(choice.value, value); });\n            if (foundChoice && !foundChoice.disabled && !foundChoice.selected) {\n                this._addItem(foundChoice, true, userTriggered);\n                return true;\n            }\n            return false;\n        };\n        Choices.prototype._generatePlaceholderValue = function () {\n            var config = this.config;\n            if (!config.placeholder) {\n                return null;\n            }\n            if (this._hasNonChoicePlaceholder) {\n                return config.placeholderValue;\n            }\n            if (this._isSelectElement) {\n                var placeholderOption = this.passedElement.placeholderOption;\n                return placeholderOption ? placeholderOption.text : null;\n            }\n            return null;\n        };\n        Choices.prototype._warnChoicesInitFailed = function (caller) {\n            if (this.config.silent) {\n                return;\n            }\n            if (!this.initialised) {\n                throw new TypeError(\"\".concat(caller, \" called on a non-initialised instance of Choices\"));\n            }\n            else if (!this.initialisedOK) {\n                throw new TypeError(\"\".concat(caller, \" called for an element which has multiple instances of Choices initialised on it\"));\n            }\n        };\n        Choices.version = '11.2.1';\n        return Choices;\n    }());\n\n    return Choices;\n\n}));\n"
  },
  {
    "path": "public/assets/scripts/choices.mjs",
    "content": "/*! choices.js v11.2.1 | © 2026 Josh Johnson | https://github.com/Choices-js/Choices#readme */\n\n/******************************************************************************\nCopyright (c) Microsoft Corporation.\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\nPERFORMANCE OF THIS SOFTWARE.\n***************************************************************************** */\n/* global Reflect, Promise, SuppressedError, Symbol */\n\nvar extendStatics = function (d, b) {\n  extendStatics = Object.setPrototypeOf || {\n    __proto__: []\n  } instanceof Array && function (d, b) {\n    d.__proto__ = b;\n  } || function (d, b) {\n    for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p];\n  };\n  return extendStatics(d, b);\n};\nfunction __extends(d, b) {\n  if (typeof b !== \"function\" && b !== null) throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\n  extendStatics(d, b);\n  function __() {\n    this.constructor = d;\n  }\n  d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\n}\nvar __assign = function () {\n  __assign = Object.assign || function __assign(t) {\n    for (var s, i = 1, n = arguments.length; i < n; i++) {\n      s = arguments[i];\n      for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\n    }\n    return t;\n  };\n  return __assign.apply(this, arguments);\n};\nfunction __spreadArray(to, from, pack) {\n  if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\n    if (ar || !(i in from)) {\n      if (!ar) ar = Array.prototype.slice.call(from, 0, i);\n      ar[i] = from[i];\n    }\n  }\n  return to.concat(ar || Array.prototype.slice.call(from));\n}\ntypeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\n  var e = new Error(message);\n  return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\n};\n\nvar ActionType = {\n    ADD_CHOICE: 'ADD_CHOICE',\n    REMOVE_CHOICE: 'REMOVE_CHOICE',\n    FILTER_CHOICES: 'FILTER_CHOICES',\n    ACTIVATE_CHOICES: 'ACTIVATE_CHOICES',\n    CLEAR_CHOICES: 'CLEAR_CHOICES',\n    ADD_GROUP: 'ADD_GROUP',\n    ADD_ITEM: 'ADD_ITEM',\n    REMOVE_ITEM: 'REMOVE_ITEM',\n    HIGHLIGHT_ITEM: 'HIGHLIGHT_ITEM',\n};\n\nvar EventType = {\n    showDropdown: 'showDropdown',\n    hideDropdown: 'hideDropdown',\n    change: 'change',\n    choice: 'choice',\n    search: 'search',\n    addItem: 'addItem',\n    removeItem: 'removeItem',\n    highlightItem: 'highlightItem',\n    highlightChoice: 'highlightChoice',\n    unhighlightItem: 'unhighlightItem',\n};\n\nvar KeyCodeMap = {\n    TAB_KEY: 9,\n    SHIFT_KEY: 16,\n    BACK_KEY: 46,\n    DELETE_KEY: 8,\n    ENTER_KEY: 13,\n    A_KEY: 65,\n    ESC_KEY: 27,\n    UP_KEY: 38,\n    DOWN_KEY: 40,\n    PAGE_UP_KEY: 33,\n    PAGE_DOWN_KEY: 34,\n};\n\nvar ObjectsInConfig = ['fuseOptions', 'classNames'];\n\nvar PassedElementTypes = {\n    Text: 'text',\n    SelectOne: 'select-one',\n    SelectMultiple: 'select-multiple',\n};\n\nvar addChoice = function (choice) { return ({\n    type: ActionType.ADD_CHOICE,\n    choice: choice,\n}); };\nvar removeChoice = function (choice) { return ({\n    type: ActionType.REMOVE_CHOICE,\n    choice: choice,\n}); };\nvar filterChoices = function (results) { return ({\n    type: ActionType.FILTER_CHOICES,\n    results: results,\n}); };\nvar activateChoices = function (active) {\n    return ({\n        type: ActionType.ACTIVATE_CHOICES,\n        active: active,\n    });\n};\n\nvar addGroup = function (group) { return ({\n    type: ActionType.ADD_GROUP,\n    group: group,\n}); };\n\nvar addItem = function (item) { return ({\n    type: ActionType.ADD_ITEM,\n    item: item,\n}); };\nvar removeItem$1 = function (item) { return ({\n    type: ActionType.REMOVE_ITEM,\n    item: item,\n}); };\nvar highlightItem = function (item, highlighted) { return ({\n    type: ActionType.HIGHLIGHT_ITEM,\n    item: item,\n    highlighted: highlighted,\n}); };\n\nvar getRandomNumber = function (min, max) { return Math.floor(Math.random() * (max - min) + min); };\nvar generateChars = function (length) {\n    return Array.from({ length: length }, function () { return getRandomNumber(0, 36).toString(36); }).join('');\n};\nvar generateId = function (element, prefix) {\n    var id = element.id || (element.name && \"\".concat(element.name, \"-\").concat(generateChars(2))) || generateChars(4);\n    id = id.replace(/(:|\\.|\\[|\\]|,)/g, '');\n    id = \"\".concat(prefix, \"-\").concat(id);\n    return id;\n};\nvar getAdjacentEl = function (startEl, selector, direction) {\n    if (direction === void 0) { direction = 1; }\n    var prop = \"\".concat(direction > 0 ? 'next' : 'previous', \"ElementSibling\");\n    var sibling = startEl[prop];\n    while (sibling) {\n        if (sibling.matches(selector)) {\n            return sibling;\n        }\n        sibling = sibling[prop];\n    }\n    return null;\n};\nvar isScrolledIntoView = function (element, parent, direction) {\n    if (direction === void 0) { direction = 1; }\n    var isVisible;\n    if (direction > 0) {\n        // In view from bottom\n        isVisible = parent.scrollTop + parent.offsetHeight >= element.offsetTop + element.offsetHeight;\n    }\n    else {\n        // In view from top\n        isVisible = element.offsetTop >= parent.scrollTop;\n    }\n    return isVisible;\n};\nvar sanitise = function (value) {\n    if (typeof value !== 'string') {\n        if (value === null || value === undefined) {\n            return '';\n        }\n        if (typeof value === 'object') {\n            if ('raw' in value) {\n                return sanitise(value.raw);\n            }\n            if ('trusted' in value) {\n                return value.trusted;\n            }\n        }\n        return value;\n    }\n    return value\n        .replace(/&/g, '&amp;')\n        .replace(/>/g, '&gt;')\n        .replace(/</g, '&lt;')\n        .replace(/'/g, '&#039;')\n        .replace(/\"/g, '&quot;');\n};\nvar strToEl = (function () {\n    var tmpEl = document.createElement('div');\n    return function (str) {\n        tmpEl.innerHTML = str.trim();\n        var firstChild = tmpEl.children[0];\n        while (tmpEl.firstChild) {\n            tmpEl.removeChild(tmpEl.firstChild);\n        }\n        return firstChild;\n    };\n})();\nvar resolveStringFunction = function (fn) {\n    return typeof fn === 'function' ? fn() : fn;\n};\nvar unwrapStringForRaw = function (s) {\n    if (typeof s === 'string') {\n        return s;\n    }\n    if (typeof s === 'object') {\n        if ('trusted' in s) {\n            return s.trusted;\n        }\n        if ('raw' in s) {\n            return s.raw;\n        }\n    }\n    return '';\n};\nvar unwrapStringForEscaped = function (s) {\n    if (typeof s === 'string') {\n        return s;\n    }\n    if (typeof s === 'object') {\n        if ('escaped' in s) {\n            return s.escaped;\n        }\n        if ('trusted' in s) {\n            return s.trusted;\n        }\n    }\n    return '';\n};\nvar getChoiceForOutput = function (choice, keyCode) {\n    return {\n        id: choice.id,\n        highlighted: choice.highlighted,\n        labelClass: choice.labelClass,\n        labelDescription: unwrapStringForRaw(choice.labelDescription),\n        customProperties: choice.customProperties,\n        disabled: choice.disabled,\n        active: choice.active,\n        label: choice.label,\n        placeholder: choice.placeholder,\n        value: choice.value,\n        groupValue: choice.group ? choice.group.label : undefined,\n        element: choice.element,\n        keyCode: keyCode,\n    };\n};\nvar resolveNoticeFunction = function (fn, value, item) {\n    return typeof fn === 'function' ? fn(sanitise(value), unwrapStringForRaw(value), item) : fn;\n};\nvar escapeForTemplate = function (allowHTML, s) {\n    return allowHTML ? unwrapStringForEscaped(s) : sanitise(s);\n};\nvar setElementHtml = function (el, allowHtml, html) {\n    el.innerHTML = escapeForTemplate(allowHtml, html);\n};\nvar sortByAlpha = function (_a, _b) {\n    var value = _a.value, _c = _a.label, label = _c === void 0 ? value : _c;\n    var value2 = _b.value, _d = _b.label, label2 = _d === void 0 ? value2 : _d;\n    return unwrapStringForRaw(label).localeCompare(unwrapStringForRaw(label2), [], {\n        sensitivity: 'base',\n        ignorePunctuation: true,\n        numeric: true,\n    });\n};\nvar sortByRank = function (a, b) {\n    return a.rank - b.rank;\n};\nvar dispatchEvent = function (element, type, customArgs) {\n    if (customArgs === void 0) { customArgs = null; }\n    var event = new CustomEvent(type, {\n        detail: customArgs,\n        bubbles: true,\n        cancelable: true,\n    });\n    return element.dispatchEvent(event);\n};\n/**\n * Returns an array of keys present on the first but missing on the second object\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nvar diff = function (a, b) {\n    var aKeys = Object.keys(a).sort();\n    var bKeys = Object.keys(b).sort();\n    return aKeys.filter(function (i) { return bKeys.indexOf(i) < 0; });\n};\nvar getClassNames = function (ClassNames) {\n    return Array.isArray(ClassNames) ? ClassNames : [ClassNames];\n};\nvar getClassNamesSelector = function (option) {\n    if (option && Array.isArray(option)) {\n        return option\n            .map(function (item) {\n            return \".\".concat(item);\n        })\n            .join('');\n    }\n    return \".\".concat(option);\n};\nvar addClassesToElement = function (element, className) {\n    var _a;\n    (_a = element.classList).add.apply(_a, getClassNames(className));\n};\nvar removeClassesFromElement = function (element, className) {\n    var _a;\n    (_a = element.classList).remove.apply(_a, getClassNames(className));\n};\nvar parseCustomProperties = function (customProperties) {\n    if (typeof customProperties !== 'undefined') {\n        try {\n            return JSON.parse(customProperties);\n        }\n        catch (e) {\n            return customProperties;\n        }\n    }\n    return {};\n};\nvar updateClassList = function (item, add, remove) {\n    var itemEl = item.itemEl;\n    if (itemEl) {\n        removeClassesFromElement(itemEl, remove);\n        addClassesToElement(itemEl, add);\n    }\n};\n\nvar Dropdown = /** @class */ (function () {\n    function Dropdown(_a) {\n        var element = _a.element, type = _a.type, classNames = _a.classNames;\n        this.element = element;\n        this.classNames = classNames;\n        this.type = type;\n        this.isActive = false;\n    }\n    /**\n     * Show dropdown to user by adding active state class\n     */\n    Dropdown.prototype.show = function () {\n        addClassesToElement(this.element, this.classNames.activeState);\n        this.element.setAttribute('aria-expanded', 'true');\n        this.isActive = true;\n        return this;\n    };\n    /**\n     * Hide dropdown from user\n     */\n    Dropdown.prototype.hide = function () {\n        removeClassesFromElement(this.element, this.classNames.activeState);\n        this.element.setAttribute('aria-expanded', 'false');\n        this.isActive = false;\n        return this;\n    };\n    return Dropdown;\n}());\n\nvar Container = /** @class */ (function () {\n    function Container(_a) {\n        var element = _a.element, type = _a.type, classNames = _a.classNames, position = _a.position;\n        this.element = element;\n        this.classNames = classNames;\n        this.type = type;\n        this.position = position;\n        this.isOpen = false;\n        this.isFlipped = false;\n        this.isDisabled = false;\n        this.isLoading = false;\n    }\n    /**\n     * Determine whether container should be flipped based on passed\n     * dropdown position\n     */\n    Container.prototype.shouldFlip = function (dropdownPos, dropdownHeight) {\n        // If flip is enabled and the dropdown bottom position is\n        // greater than the window height flip the dropdown.\n        var shouldFlip = false;\n        if (this.position === 'auto') {\n            shouldFlip =\n                this.element.getBoundingClientRect().top - dropdownHeight >= 0 &&\n                    !window.matchMedia(\"(min-height: \".concat(dropdownPos + 1, \"px)\")).matches;\n        }\n        else if (this.position === 'top') {\n            shouldFlip = true;\n        }\n        return shouldFlip;\n    };\n    Container.prototype.setActiveDescendant = function (activeDescendantID) {\n        this.element.setAttribute('aria-activedescendant', activeDescendantID);\n    };\n    Container.prototype.removeActiveDescendant = function () {\n        this.element.removeAttribute('aria-activedescendant');\n    };\n    Container.prototype.open = function (dropdownPos, dropdownHeight) {\n        addClassesToElement(this.element, this.classNames.openState);\n        this.element.setAttribute('aria-expanded', 'true');\n        this.isOpen = true;\n        if (this.shouldFlip(dropdownPos, dropdownHeight)) {\n            addClassesToElement(this.element, this.classNames.flippedState);\n            this.isFlipped = true;\n        }\n    };\n    Container.prototype.close = function () {\n        removeClassesFromElement(this.element, this.classNames.openState);\n        this.element.setAttribute('aria-expanded', 'false');\n        this.removeActiveDescendant();\n        this.isOpen = false;\n        // A dropdown flips if it does not have space within the page\n        if (this.isFlipped) {\n            removeClassesFromElement(this.element, this.classNames.flippedState);\n            this.isFlipped = false;\n        }\n    };\n    Container.prototype.addFocusState = function () {\n        addClassesToElement(this.element, this.classNames.focusState);\n    };\n    Container.prototype.removeFocusState = function () {\n        removeClassesFromElement(this.element, this.classNames.focusState);\n    };\n    Container.prototype.addInvalidState = function () {\n        addClassesToElement(this.element, this.classNames.invalidState);\n    };\n    Container.prototype.removeInvalidState = function () {\n        removeClassesFromElement(this.element, this.classNames.invalidState);\n    };\n    Container.prototype.enable = function () {\n        removeClassesFromElement(this.element, this.classNames.disabledState);\n        this.element.removeAttribute('aria-disabled');\n        if (this.type === PassedElementTypes.SelectOne) {\n            this.element.setAttribute('tabindex', '0');\n        }\n        this.isDisabled = false;\n    };\n    Container.prototype.disable = function () {\n        addClassesToElement(this.element, this.classNames.disabledState);\n        this.element.setAttribute('aria-disabled', 'true');\n        if (this.type === PassedElementTypes.SelectOne) {\n            this.element.setAttribute('tabindex', '-1');\n        }\n        this.isDisabled = true;\n    };\n    Container.prototype.wrap = function (element) {\n        var el = this.element;\n        var parentNode = element.parentNode;\n        if (parentNode) {\n            if (element.nextSibling) {\n                parentNode.insertBefore(el, element.nextSibling);\n            }\n            else {\n                parentNode.appendChild(el);\n            }\n        }\n        el.appendChild(element);\n    };\n    Container.prototype.unwrap = function (element) {\n        var el = this.element;\n        var parentNode = el.parentNode;\n        if (parentNode) {\n            // Move passed element outside this element\n            parentNode.insertBefore(element, el);\n            // Remove this element\n            parentNode.removeChild(el);\n        }\n    };\n    Container.prototype.addLoadingState = function () {\n        addClassesToElement(this.element, this.classNames.loadingState);\n        this.element.setAttribute('aria-busy', 'true');\n        this.isLoading = true;\n    };\n    Container.prototype.removeLoadingState = function () {\n        removeClassesFromElement(this.element, this.classNames.loadingState);\n        this.element.removeAttribute('aria-busy');\n        this.isLoading = false;\n    };\n    return Container;\n}());\n\nvar Input = /** @class */ (function () {\n    function Input(_a) {\n        var element = _a.element, type = _a.type, classNames = _a.classNames, preventPaste = _a.preventPaste;\n        this.element = element;\n        this.type = type;\n        this.classNames = classNames;\n        this.preventPaste = preventPaste;\n        this.isFocussed = this.element.isEqualNode(document.activeElement);\n        this.isDisabled = element.disabled;\n        this._onPaste = this._onPaste.bind(this);\n        this._onInput = this._onInput.bind(this);\n        this._onFocus = this._onFocus.bind(this);\n        this._onBlur = this._onBlur.bind(this);\n    }\n    Object.defineProperty(Input.prototype, \"placeholder\", {\n        set: function (placeholder) {\n            this.element.placeholder = placeholder;\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(Input.prototype, \"value\", {\n        get: function () {\n            return this.element.value;\n        },\n        set: function (value) {\n            this.element.value = value;\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Input.prototype.addEventListeners = function () {\n        var el = this.element;\n        el.addEventListener('paste', this._onPaste);\n        el.addEventListener('input', this._onInput, {\n            passive: true,\n        });\n        el.addEventListener('focus', this._onFocus, {\n            passive: true,\n        });\n        el.addEventListener('blur', this._onBlur, {\n            passive: true,\n        });\n    };\n    Input.prototype.removeEventListeners = function () {\n        var el = this.element;\n        el.removeEventListener('input', this._onInput);\n        el.removeEventListener('paste', this._onPaste);\n        el.removeEventListener('focus', this._onFocus);\n        el.removeEventListener('blur', this._onBlur);\n    };\n    Input.prototype.enable = function () {\n        var el = this.element;\n        el.removeAttribute('disabled');\n        this.isDisabled = false;\n    };\n    Input.prototype.disable = function () {\n        var el = this.element;\n        el.setAttribute('disabled', '');\n        this.isDisabled = true;\n    };\n    Input.prototype.focus = function () {\n        if (!this.isFocussed) {\n            this.element.focus();\n        }\n    };\n    Input.prototype.blur = function () {\n        if (this.isFocussed) {\n            this.element.blur();\n        }\n    };\n    Input.prototype.clear = function (setWidth) {\n        if (setWidth === void 0) { setWidth = true; }\n        this.element.value = '';\n        if (setWidth) {\n            this.setWidth();\n        }\n        return this;\n    };\n    /**\n     * Set the correct input width based on placeholder\n     * value or input value\n     */\n    Input.prototype.setWidth = function () {\n        // Resize input to contents or placeholder\n        var element = this.element;\n        element.style.minWidth = \"\".concat(element.placeholder.length + 1, \"ch\");\n        element.style.width = \"\".concat(element.value.length + 1, \"ch\");\n    };\n    Input.prototype.setActiveDescendant = function (activeDescendantID) {\n        this.element.setAttribute('aria-activedescendant', activeDescendantID);\n    };\n    Input.prototype.removeActiveDescendant = function () {\n        this.element.removeAttribute('aria-activedescendant');\n    };\n    Input.prototype._onInput = function () {\n        if (this.type !== PassedElementTypes.SelectOne) {\n            this.setWidth();\n        }\n    };\n    Input.prototype._onPaste = function (event) {\n        if (this.preventPaste) {\n            event.preventDefault();\n        }\n    };\n    Input.prototype._onFocus = function () {\n        this.isFocussed = true;\n    };\n    Input.prototype._onBlur = function () {\n        this.isFocussed = false;\n    };\n    return Input;\n}());\n\nvar SCROLLING_SPEED = 4;\n\nvar List = /** @class */ (function () {\n    function List(_a) {\n        var element = _a.element;\n        this.element = element;\n        this.scrollPos = this.element.scrollTop;\n        this.height = this.element.offsetHeight;\n    }\n    List.prototype.prepend = function (node) {\n        var child = this.element.firstElementChild;\n        if (child) {\n            this.element.insertBefore(node, child);\n        }\n        else {\n            this.element.append(node);\n        }\n    };\n    List.prototype.scrollToTop = function () {\n        this.element.scrollTop = 0;\n    };\n    List.prototype.scrollToChildElement = function (element, direction) {\n        var _this = this;\n        if (!element) {\n            return;\n        }\n        var listHeight = this.element.offsetHeight;\n        // Scroll position of dropdown\n        var listScrollPosition = this.element.scrollTop + listHeight;\n        var elementHeight = element.offsetHeight;\n        // Distance from bottom of element to top of parent\n        var elementPos = element.offsetTop + elementHeight;\n        // Difference between the element and scroll position\n        var destination = direction > 0 ? this.element.scrollTop + elementPos - listScrollPosition : element.offsetTop;\n        requestAnimationFrame(function () {\n            _this._animateScroll(destination, direction);\n        });\n    };\n    List.prototype._scrollDown = function (scrollPos, strength, destination) {\n        var easing = (destination - scrollPos) / strength;\n        var distance = easing > 1 ? easing : 1;\n        this.element.scrollTop = scrollPos + distance;\n    };\n    List.prototype._scrollUp = function (scrollPos, strength, destination) {\n        var easing = (scrollPos - destination) / strength;\n        var distance = easing > 1 ? easing : 1;\n        this.element.scrollTop = scrollPos - distance;\n    };\n    List.prototype._animateScroll = function (destination, direction) {\n        var _this = this;\n        var strength = SCROLLING_SPEED;\n        var choiceListScrollTop = this.element.scrollTop;\n        var continueAnimation = false;\n        if (direction > 0) {\n            this._scrollDown(choiceListScrollTop, strength, destination);\n            if (choiceListScrollTop < destination) {\n                continueAnimation = true;\n            }\n        }\n        else {\n            this._scrollUp(choiceListScrollTop, strength, destination);\n            if (choiceListScrollTop > destination) {\n                continueAnimation = true;\n            }\n        }\n        if (continueAnimation) {\n            requestAnimationFrame(function () {\n                _this._animateScroll(destination, direction);\n            });\n        }\n    };\n    return List;\n}());\n\nvar WrappedElement = /** @class */ (function () {\n    function WrappedElement(_a) {\n        var element = _a.element, classNames = _a.classNames;\n        this.element = element;\n        this.classNames = classNames;\n        this.isDisabled = false;\n    }\n    Object.defineProperty(WrappedElement.prototype, \"isActive\", {\n        get: function () {\n            return this.element.dataset.choice === 'active';\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(WrappedElement.prototype, \"dir\", {\n        get: function () {\n            return this.element.dir;\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(WrappedElement.prototype, \"value\", {\n        get: function () {\n            return this.element.value;\n        },\n        set: function (value) {\n            this.element.setAttribute('value', value);\n            this.element.value = value;\n        },\n        enumerable: false,\n        configurable: true\n    });\n    WrappedElement.prototype.conceal = function () {\n        var el = this.element;\n        // Hide passed input\n        addClassesToElement(el, this.classNames.input);\n        el.hidden = true;\n        // Remove element from tab index\n        el.tabIndex = -1;\n        // Backup original styles if any\n        var origStyle = el.getAttribute('style');\n        if (origStyle) {\n            el.setAttribute('data-choice-orig-style', origStyle);\n        }\n        el.setAttribute('data-choice', 'active');\n    };\n    WrappedElement.prototype.reveal = function () {\n        var el = this.element;\n        // Reinstate passed element\n        removeClassesFromElement(el, this.classNames.input);\n        el.hidden = false;\n        el.removeAttribute('tabindex');\n        // Recover original styles if any\n        var origStyle = el.getAttribute('data-choice-orig-style');\n        if (origStyle) {\n            el.removeAttribute('data-choice-orig-style');\n            el.setAttribute('style', origStyle);\n        }\n        else {\n            el.removeAttribute('style');\n        }\n        el.removeAttribute('data-choice');\n    };\n    WrappedElement.prototype.enable = function () {\n        this.element.removeAttribute('disabled');\n        this.element.disabled = false;\n        this.isDisabled = false;\n    };\n    WrappedElement.prototype.disable = function () {\n        this.element.setAttribute('disabled', '');\n        this.element.disabled = true;\n        this.isDisabled = true;\n    };\n    WrappedElement.prototype.triggerEvent = function (eventType, data) {\n        dispatchEvent(this.element, eventType, data || {});\n    };\n    return WrappedElement;\n}());\n\nvar WrappedInput = /** @class */ (function (_super) {\n    __extends(WrappedInput, _super);\n    function WrappedInput() {\n        return _super !== null && _super.apply(this, arguments) || this;\n    }\n    return WrappedInput;\n}(WrappedElement));\n\nvar coerceBool = function (arg, defaultValue) {\n    if (defaultValue === void 0) { defaultValue = true; }\n    return typeof arg === 'undefined' ? defaultValue : !!arg;\n};\nvar stringToHtmlClass = function (input) {\n    if (typeof input === 'string') {\n        // eslint-disable-next-line no-param-reassign\n        input = input.split(' ').filter(function (s) { return s.length; });\n    }\n    if (Array.isArray(input) && input.length) {\n        return input;\n    }\n    return undefined;\n};\nvar mapInputToChoice = function (value, allowGroup, allowRawString) {\n    if (allowRawString === void 0) { allowRawString = true; }\n    if (typeof value === 'string') {\n        var sanitisedValue = sanitise(value);\n        var userValue = allowRawString || sanitisedValue === value ? value : { escaped: sanitisedValue, raw: value };\n        var result_1 = mapInputToChoice({\n            value: value,\n            label: userValue,\n            selected: true,\n        }, false);\n        return result_1;\n    }\n    var groupOrChoice = value;\n    if ('choices' in groupOrChoice) {\n        if (!allowGroup) {\n            // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/optgroup\n            throw new TypeError(\"optGroup is not allowed\");\n        }\n        var group = groupOrChoice;\n        var choices = group.choices.map(function (e) { return mapInputToChoice(e, false); });\n        var result_2 = {\n            id: 0, // actual ID will be assigned during _addGroup\n            label: unwrapStringForRaw(group.label) || group.value,\n            active: !!choices.length,\n            disabled: !!group.disabled,\n            choices: choices,\n        };\n        return result_2;\n    }\n    var choice = groupOrChoice;\n    var result = {\n        id: 0, // actual ID will be assigned during _addChoice\n        group: null, // actual group will be assigned during _addGroup but before _addChoice\n        score: 0, // used in search\n        rank: 0, // used in search, stable sort order\n        value: choice.value,\n        label: choice.label || choice.value,\n        active: coerceBool(choice.active),\n        selected: coerceBool(choice.selected, false),\n        disabled: coerceBool(choice.disabled, false),\n        placeholder: coerceBool(choice.placeholder, false),\n        highlighted: false,\n        labelClass: stringToHtmlClass(choice.labelClass),\n        labelDescription: choice.labelDescription,\n        customProperties: choice.customProperties,\n    };\n    return result;\n};\n\nvar isHtmlInputElement = function (e) { return e.tagName === 'INPUT'; };\nvar isHtmlSelectElement = function (e) { return e.tagName === 'SELECT'; };\nvar isHtmlOption = function (e) { return e.tagName === 'OPTION'; };\nvar isHtmlOptgroup = function (e) { return e.tagName === 'OPTGROUP'; };\n\nvar WrappedSelect = /** @class */ (function (_super) {\n    __extends(WrappedSelect, _super);\n    function WrappedSelect(_a) {\n        var element = _a.element, classNames = _a.classNames, template = _a.template, extractPlaceholder = _a.extractPlaceholder;\n        var _this = _super.call(this, { element: element, classNames: classNames }) || this;\n        _this.template = template;\n        _this.extractPlaceholder = extractPlaceholder;\n        return _this;\n    }\n    Object.defineProperty(WrappedSelect.prototype, \"placeholderOption\", {\n        get: function () {\n            return (this.element.querySelector('option[value=\"\"]') ||\n                // Backward compatibility layer for the non-standard placeholder attribute supported in older versions.\n                this.element.querySelector('option[placeholder]'));\n        },\n        enumerable: false,\n        configurable: true\n    });\n    WrappedSelect.prototype.addOptions = function (choices) {\n        var _this = this;\n        var fragment = document.createDocumentFragment();\n        choices.forEach(function (obj) {\n            var choice = obj;\n            if (choice.element) {\n                return;\n            }\n            var option = _this.template(choice);\n            fragment.appendChild(option);\n            choice.element = option;\n        });\n        this.element.appendChild(fragment);\n    };\n    WrappedSelect.prototype.optionsAsChoices = function () {\n        var _this = this;\n        var choices = [];\n        this.element.querySelectorAll(':scope > option, :scope > optgroup').forEach(function (e) {\n            if (isHtmlOption(e)) {\n                choices.push(_this._optionToChoice(e));\n            }\n            else if (isHtmlOptgroup(e)) {\n                choices.push(_this._optgroupToChoice(e));\n            }\n            // todo: hr as empty optgroup, requires displaying empty opt-groups to be useful\n        });\n        return choices;\n    };\n    // eslint-disable-next-line class-methods-use-this\n    WrappedSelect.prototype._optionToChoice = function (option) {\n        // option.value returns the label if there is no value attribute, which can break legacy placeholder attribute support\n        if (!option.hasAttribute('value') && option.hasAttribute('placeholder')) {\n            option.setAttribute('value', '');\n            option.value = '';\n        }\n        return {\n            id: 0,\n            group: null,\n            score: 0,\n            rank: 0,\n            value: option.value,\n            // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/option\n            // This attribute is text for the label indicating the meaning of the option. If the `label` attribute isn't defined, its value is that of the element text content (ie `innerText`).\n            label: option.label,\n            element: option,\n            active: true,\n            // this returns true if nothing is selected on initial load, which will break placeholder support\n            selected: this.extractPlaceholder ? option.selected : option.hasAttribute('selected'),\n            disabled: option.disabled,\n            highlighted: false,\n            placeholder: this.extractPlaceholder && (!option.value || option.hasAttribute('placeholder')),\n            labelClass: typeof option.dataset.labelClass !== 'undefined' ? stringToHtmlClass(option.dataset.labelClass) : undefined,\n            labelDescription: typeof option.dataset.labelDescription !== 'undefined'\n                ? { trusted: option.dataset.labelDescription }\n                : undefined,\n            customProperties: parseCustomProperties(option.dataset.customProperties),\n        };\n    };\n    WrappedSelect.prototype._optgroupToChoice = function (optgroup) {\n        var _this = this;\n        var options = optgroup.querySelectorAll('option');\n        var choices = Array.from(options).map(function (option) { return _this._optionToChoice(option); });\n        return {\n            id: 0,\n            label: optgroup.label || '',\n            element: optgroup,\n            active: !!choices.length,\n            disabled: optgroup.disabled,\n            choices: choices,\n        };\n    };\n    return WrappedSelect;\n}(WrappedElement));\n\nvar DEFAULT_CLASSNAMES = {\n    containerOuter: ['choices'],\n    containerInner: ['choices__inner'],\n    input: ['choices__input'],\n    inputCloned: ['choices__input--cloned'],\n    list: ['choices__list'],\n    listItems: ['choices__list--multiple'],\n    listSingle: ['choices__list--single'],\n    listDropdown: ['choices__list--dropdown'],\n    item: ['choices__item'],\n    itemSelectable: ['choices__item--selectable'],\n    itemDisabled: ['choices__item--disabled'],\n    itemChoice: ['choices__item--choice'],\n    description: ['choices__description'],\n    placeholder: ['choices__placeholder'],\n    group: ['choices__group'],\n    groupHeading: ['choices__heading'],\n    button: ['choices__button'],\n    activeState: ['is-active'],\n    focusState: ['is-focused'],\n    openState: ['is-open'],\n    disabledState: ['is-disabled'],\n    highlightedState: ['is-highlighted'],\n    selectedState: ['is-selected'],\n    flippedState: ['is-flipped'],\n    loadingState: ['is-loading'],\n    invalidState: ['is-invalid'],\n    notice: ['choices__notice'],\n    addChoice: ['choices__item--selectable', 'add-choice'],\n    noResults: ['has-no-results'],\n    noChoices: ['has-no-choices'],\n};\nvar DEFAULT_CONFIG = {\n    items: [],\n    choices: [],\n    silent: false,\n    renderChoiceLimit: -1,\n    maxItemCount: -1,\n    closeDropdownOnSelect: 'auto',\n    singleModeForMultiSelect: false,\n    addChoices: false,\n    addItems: true,\n    addItemFilter: function (value) { return !!value && value !== ''; },\n    removeItems: true,\n    removeItemButton: false,\n    removeItemButtonAlignLeft: false,\n    editItems: false,\n    allowHTML: false,\n    allowHtmlUserInput: false,\n    duplicateItemsAllowed: true,\n    delimiter: ',',\n    paste: true,\n    searchEnabled: true,\n    searchChoices: true,\n    searchDisabledChoices: false,\n    searchFloor: 1,\n    searchResultLimit: 4,\n    searchFields: ['label', 'value'],\n    position: 'auto',\n    resetScrollPosition: true,\n    shouldSort: true,\n    shouldSortItems: false,\n    sorter: sortByAlpha,\n    shadowRoot: null,\n    placeholder: true,\n    placeholderValue: null,\n    searchPlaceholderValue: null,\n    prependValue: null,\n    appendValue: null,\n    renderSelectedChoices: 'auto',\n    searchRenderSelectedChoices: true,\n    loadingText: 'Loading...',\n    noResultsText: 'No results found',\n    noChoicesText: 'No choices to choose from',\n    itemSelectText: 'Press to select',\n    uniqueItemText: 'Only unique values can be added',\n    customAddItemText: 'Only values matching specific conditions can be added',\n    addItemText: function (value) { return \"Press Enter to add <b>\\\"\".concat(value, \"\\\"</b>\"); },\n    removeItemIconText: function () { return \"Remove item\"; },\n    removeItemLabelText: function (value, _valueRaw, i) {\n        return \"Remove item: \".concat(i ? sanitise(i.label) : value);\n    },\n    maxItemText: function (maxItemCount) { return \"Only \".concat(maxItemCount, \" values can be added\"); },\n    valueComparer: function (value1, value2) { return value1 === value2; },\n    fuseOptions: {\n        includeScore: true,\n    },\n    labelId: '',\n    callbackOnInit: null,\n    callbackOnCreateTemplates: null,\n    classNames: DEFAULT_CLASSNAMES,\n    appendGroupInSearch: false,\n};\n\nvar removeItem = function (item) {\n    var itemEl = item.itemEl;\n    if (itemEl) {\n        itemEl.remove();\n        item.itemEl = undefined;\n    }\n};\nfunction items(s, action, context) {\n    var state = s;\n    var update = true;\n    switch (action.type) {\n        case ActionType.ADD_ITEM: {\n            action.item.selected = true;\n            var el = action.item.element;\n            if (el) {\n                el.selected = true;\n                el.setAttribute('selected', '');\n            }\n            state.push(action.item);\n            break;\n        }\n        case ActionType.REMOVE_ITEM: {\n            action.item.selected = false;\n            var el = action.item.element;\n            if (el) {\n                el.selected = false;\n                el.removeAttribute('selected');\n                // For a select-one, if all options are deselected, the first item is selected. To set a black value, select.value needs to be set\n                var select = el.parentElement;\n                if (select && isHtmlSelectElement(select) && select.type === PassedElementTypes.SelectOne) {\n                    select.value = '';\n                }\n            }\n            // this is mixing concerns, but this is *so much faster*\n            removeItem(action.item);\n            state = state.filter(function (choice) { return choice.id !== action.item.id; });\n            break;\n        }\n        case ActionType.REMOVE_CHOICE: {\n            removeItem(action.choice);\n            state = state.filter(function (item) { return item.id !== action.choice.id; });\n            break;\n        }\n        case ActionType.HIGHLIGHT_ITEM: {\n            var highlighted = action.highlighted;\n            var item = state.find(function (obj) { return obj.id === action.item.id; });\n            if (item && item.highlighted !== highlighted) {\n                item.highlighted = highlighted;\n                if (context) {\n                    updateClassList(item, highlighted ? context.classNames.highlightedState : context.classNames.selectedState, highlighted ? context.classNames.selectedState : context.classNames.highlightedState);\n                }\n            }\n            break;\n        }\n        default: {\n            update = false;\n            break;\n        }\n    }\n    return { state: state, update: update };\n}\n\nfunction groups(s, action) {\n    var state = s;\n    var update = true;\n    switch (action.type) {\n        case ActionType.ADD_GROUP: {\n            state.push(action.group);\n            break;\n        }\n        case ActionType.CLEAR_CHOICES: {\n            state = [];\n            break;\n        }\n        default: {\n            update = false;\n            break;\n        }\n    }\n    return { state: state, update: update };\n}\n\n/* eslint-disable */\nfunction choices(s, action, context) {\n    var state = s;\n    var update = true;\n    switch (action.type) {\n        case ActionType.ADD_CHOICE: {\n            state.push(action.choice);\n            break;\n        }\n        case ActionType.REMOVE_CHOICE: {\n            action.choice.choiceEl = undefined;\n            if (action.choice.group) {\n                action.choice.group.choices = action.choice.group.choices.filter(function (obj) { return obj.id !== action.choice.id; });\n            }\n            state = state.filter(function (obj) { return obj.id !== action.choice.id; });\n            break;\n        }\n        case ActionType.ADD_ITEM:\n        case ActionType.REMOVE_ITEM: {\n            action.item.choiceEl = undefined;\n            break;\n        }\n        case ActionType.FILTER_CHOICES: {\n            // avoid O(n^2) algorithm complexity when searching/filtering choices\n            var scoreLookup_1 = [];\n            action.results.forEach(function (result) {\n                scoreLookup_1[result.item.id] = result;\n            });\n            state.forEach(function (choice) {\n                var result = scoreLookup_1[choice.id];\n                if (result !== undefined) {\n                    choice.score = result.score;\n                    choice.rank = result.rank;\n                    choice.active = true;\n                }\n                else {\n                    choice.score = 0;\n                    choice.rank = 0;\n                    choice.active = false;\n                }\n                if (context && context.appendGroupInSearch) {\n                    choice.choiceEl = undefined;\n                }\n            });\n            break;\n        }\n        case ActionType.ACTIVATE_CHOICES: {\n            state.forEach(function (choice) {\n                choice.active = action.active;\n                if (context && context.appendGroupInSearch) {\n                    choice.choiceEl = undefined;\n                }\n            });\n            break;\n        }\n        case ActionType.CLEAR_CHOICES: {\n            state = [];\n            break;\n        }\n        default: {\n            update = false;\n            break;\n        }\n    }\n    return { state: state, update: update };\n}\n\nvar reducers = {\n    groups: groups,\n    items: items,\n    choices: choices,\n};\nvar Store = /** @class */ (function () {\n    function Store(context) {\n        this._state = this.defaultState;\n        this._listeners = [];\n        this._txn = 0;\n        this._context = context;\n    }\n    Object.defineProperty(Store.prototype, \"defaultState\", {\n        // eslint-disable-next-line class-methods-use-this\n        get: function () {\n            return {\n                groups: [],\n                items: [],\n                choices: [],\n            };\n        },\n        enumerable: false,\n        configurable: true\n    });\n    // eslint-disable-next-line class-methods-use-this\n    Store.prototype.changeSet = function (init) {\n        return {\n            groups: init,\n            items: init,\n            choices: init,\n        };\n    };\n    Store.prototype.reset = function () {\n        this._state = this.defaultState;\n        var changes = this.changeSet(true);\n        if (this._txn) {\n            this._changeSet = changes;\n        }\n        else {\n            this._listeners.forEach(function (l) { return l(changes); });\n        }\n    };\n    Store.prototype.subscribe = function (onChange) {\n        this._listeners.push(onChange);\n        return this;\n    };\n    Store.prototype.dispatch = function (action) {\n        var _this = this;\n        var state = this._state;\n        var hasChanges = false;\n        var changes = this._changeSet || this.changeSet(false);\n        Object.keys(reducers).forEach(function (key) {\n            var stateUpdate = reducers[key](state[key], action, _this._context);\n            if (stateUpdate.update) {\n                hasChanges = true;\n                changes[key] = true;\n                state[key] = stateUpdate.state;\n            }\n        });\n        if (hasChanges) {\n            if (this._txn) {\n                this._changeSet = changes;\n            }\n            else {\n                this._listeners.forEach(function (l) { return l(changes); });\n            }\n        }\n    };\n    Store.prototype.withTxn = function (func) {\n        this._txn++;\n        try {\n            func();\n        }\n        finally {\n            this._txn = Math.max(0, this._txn - 1);\n            if (!this._txn) {\n                var changeSet_1 = this._changeSet;\n                if (changeSet_1) {\n                    this._changeSet = undefined;\n                    this._listeners.forEach(function (l) { return l(changeSet_1); });\n                }\n            }\n        }\n    };\n    Object.defineProperty(Store.prototype, \"state\", {\n        /**\n         * Get store object\n         */\n        get: function () {\n            return this._state;\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(Store.prototype, \"items\", {\n        /**\n         * Get items from store\n         */\n        get: function () {\n            return this.state.items;\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(Store.prototype, \"highlightedActiveItems\", {\n        /**\n         * Get highlighted items from store\n         */\n        get: function () {\n            return this.items.filter(function (item) { return item.active && item.highlighted; });\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(Store.prototype, \"choices\", {\n        /**\n         * Get choices from store\n         */\n        get: function () {\n            return this.state.choices;\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(Store.prototype, \"activeChoices\", {\n        /**\n         * Get active choices from store\n         */\n        get: function () {\n            return this.choices.filter(function (choice) { return choice.active; });\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(Store.prototype, \"searchableChoices\", {\n        /**\n         * Get choices that can be searched (excluding placeholders or disabled choices)\n         */\n        get: function () {\n            var context = this._context;\n            return this.choices.filter(function (choice) { return !choice.placeholder && (context.searchDisabledChoices || !choice.disabled); });\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(Store.prototype, \"groups\", {\n        /**\n         * Get groups from store\n         */\n        get: function () {\n            return this.state.groups;\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(Store.prototype, \"activeGroups\", {\n        /**\n         * Get active groups from store\n         */\n        get: function () {\n            var _this = this;\n            return this.state.groups.filter(function (group) {\n                var isActive = group.active && !group.disabled;\n                var hasActiveOptions = _this.state.choices.some(function (choice) { return choice.active && !choice.disabled; });\n                return isActive && hasActiveOptions;\n            }, []);\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Store.prototype.inTxn = function () {\n        return this._txn > 0;\n    };\n    /**\n     * Get single choice by it's ID\n     */\n    Store.prototype.getChoiceById = function (id) {\n        return this.activeChoices.find(function (choice) { return choice.id === id; });\n    };\n    /**\n     * Get group by group id\n     */\n    Store.prototype.getGroupById = function (id) {\n        return this.groups.find(function (group) { return group.id === id; });\n    };\n    return Store;\n}());\n\nvar NoticeTypes = {\n    noChoices: 'no-choices',\n    noResults: 'no-results',\n    addChoice: 'add-choice',\n    generic: '',\n};\n\nfunction _defineProperty(e, r, t) {\n  return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {\n    value: t,\n    enumerable: true,\n    configurable: true,\n    writable: true\n  }) : e[r] = t, e;\n}\nfunction ownKeys(e, r) {\n  var t = Object.keys(e);\n  if (Object.getOwnPropertySymbols) {\n    var o = Object.getOwnPropertySymbols(e);\n    r && (o = o.filter(function (r) {\n      return Object.getOwnPropertyDescriptor(e, r).enumerable;\n    })), t.push.apply(t, o);\n  }\n  return t;\n}\nfunction _objectSpread2(e) {\n  for (var r = 1; r < arguments.length; r++) {\n    var t = null != arguments[r] ? arguments[r] : {};\n    r % 2 ? ownKeys(Object(t), true).forEach(function (r) {\n      _defineProperty(e, r, t[r]);\n    }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {\n      Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));\n    });\n  }\n  return e;\n}\nfunction _toPrimitive(t, r) {\n  if (\"object\" != typeof t || !t) return t;\n  var e = t[Symbol.toPrimitive];\n  if (void 0 !== e) {\n    var i = e.call(t, r);\n    if (\"object\" != typeof i) return i;\n    throw new TypeError(\"@@toPrimitive must return a primitive value.\");\n  }\n  return (\"string\" === r ? String : Number)(t);\n}\nfunction _toPropertyKey(t) {\n  var i = _toPrimitive(t, \"string\");\n  return \"symbol\" == typeof i ? i : i + \"\";\n}\n\n/**\n * Fuse.js v7.0.0 - Lightweight fuzzy-search (http://fusejs.io)\n *\n * Copyright (c) 2023 Kiro Risk (http://kiro.me)\n * All Rights Reserved. Apache Software License 2.0\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n */\n\nfunction isArray(value) {\n  return !Array.isArray ? getTag(value) === '[object Array]' : Array.isArray(value);\n}\nfunction baseToString(value) {\n  // Exit early for strings to avoid a performance hit in some environments.\n  if (typeof value == 'string') {\n    return value;\n  }\n  let result = value + '';\n  return result == '0' && 1 / value == -Infinity ? '-0' : result;\n}\nfunction toString(value) {\n  return value == null ? '' : baseToString(value);\n}\nfunction isString(value) {\n  return typeof value === 'string';\n}\nfunction isNumber(value) {\n  return typeof value === 'number';\n}\n\n// Adapted from: https://github.com/lodash/lodash/blob/master/isBoolean.js\nfunction isBoolean(value) {\n  return value === true || value === false || isObjectLike(value) && getTag(value) == '[object Boolean]';\n}\nfunction isObject(value) {\n  return typeof value === 'object';\n}\n\n// Checks if `value` is object-like.\nfunction isObjectLike(value) {\n  return isObject(value) && value !== null;\n}\nfunction isDefined(value) {\n  return value !== undefined && value !== null;\n}\nfunction isBlank(value) {\n  return !value.trim().length;\n}\n\n// Gets the `toStringTag` of `value`.\n// Adapted from: https://github.com/lodash/lodash/blob/master/.internal/getTag.js\nfunction getTag(value) {\n  return value == null ? value === undefined ? '[object Undefined]' : '[object Null]' : Object.prototype.toString.call(value);\n}\nconst INCORRECT_INDEX_TYPE = \"Incorrect 'index' type\";\nconst LOGICAL_SEARCH_INVALID_QUERY_FOR_KEY = key => `Invalid value for key ${key}`;\nconst PATTERN_LENGTH_TOO_LARGE = max => `Pattern length exceeds max of ${max}.`;\nconst MISSING_KEY_PROPERTY = name => `Missing ${name} property in key`;\nconst INVALID_KEY_WEIGHT_VALUE = key => `Property 'weight' in key '${key}' must be a positive integer`;\nconst hasOwn = Object.prototype.hasOwnProperty;\nclass KeyStore {\n  constructor(keys) {\n    this._keys = [];\n    this._keyMap = {};\n    let totalWeight = 0;\n    keys.forEach(key => {\n      let obj = createKey(key);\n      this._keys.push(obj);\n      this._keyMap[obj.id] = obj;\n      totalWeight += obj.weight;\n    });\n\n    // Normalize weights so that their sum is equal to 1\n    this._keys.forEach(key => {\n      key.weight /= totalWeight;\n    });\n  }\n  get(keyId) {\n    return this._keyMap[keyId];\n  }\n  keys() {\n    return this._keys;\n  }\n  toJSON() {\n    return JSON.stringify(this._keys);\n  }\n}\nfunction createKey(key) {\n  let path = null;\n  let id = null;\n  let src = null;\n  let weight = 1;\n  let getFn = null;\n  if (isString(key) || isArray(key)) {\n    src = key;\n    path = createKeyPath(key);\n    id = createKeyId(key);\n  } else {\n    if (!hasOwn.call(key, 'name')) {\n      throw new Error(MISSING_KEY_PROPERTY('name'));\n    }\n    const name = key.name;\n    src = name;\n    if (hasOwn.call(key, 'weight')) {\n      weight = key.weight;\n      if (weight <= 0) {\n        throw new Error(INVALID_KEY_WEIGHT_VALUE(name));\n      }\n    }\n    path = createKeyPath(name);\n    id = createKeyId(name);\n    getFn = key.getFn;\n  }\n  return {\n    path,\n    id,\n    weight,\n    src,\n    getFn\n  };\n}\nfunction createKeyPath(key) {\n  return isArray(key) ? key : key.split('.');\n}\nfunction createKeyId(key) {\n  return isArray(key) ? key.join('.') : key;\n}\nfunction get(obj, path) {\n  let list = [];\n  let arr = false;\n  const deepGet = (obj, path, index) => {\n    if (!isDefined(obj)) {\n      return;\n    }\n    if (!path[index]) {\n      // If there's no path left, we've arrived at the object we care about.\n      list.push(obj);\n    } else {\n      let key = path[index];\n      const value = obj[key];\n      if (!isDefined(value)) {\n        return;\n      }\n\n      // If we're at the last value in the path, and if it's a string/number/bool,\n      // add it to the list\n      if (index === path.length - 1 && (isString(value) || isNumber(value) || isBoolean(value))) {\n        list.push(toString(value));\n      } else if (isArray(value)) {\n        arr = true;\n        // Search each item in the array.\n        for (let i = 0, len = value.length; i < len; i += 1) {\n          deepGet(value[i], path, index + 1);\n        }\n      } else if (path.length) {\n        // An object. Recurse further.\n        deepGet(value, path, index + 1);\n      }\n    }\n  };\n\n  // Backwards compatibility (since path used to be a string)\n  deepGet(obj, isString(path) ? path.split('.') : path, 0);\n  return arr ? list : list[0];\n}\nconst MatchOptions = {\n  // Whether the matches should be included in the result set. When `true`, each record in the result\n  // set will include the indices of the matched characters.\n  // These can consequently be used for highlighting purposes.\n  includeMatches: false,\n  // When `true`, the matching function will continue to the end of a search pattern even if\n  // a perfect match has already been located in the string.\n  findAllMatches: false,\n  // Minimum number of characters that must be matched before a result is considered a match\n  minMatchCharLength: 1\n};\nconst BasicOptions = {\n  // When `true`, the algorithm continues searching to the end of the input even if a perfect\n  // match is found before the end of the same input.\n  isCaseSensitive: false,\n  // When true, the matching function will continue to the end of a search pattern even if\n  includeScore: false,\n  // List of properties that will be searched. This also supports nested properties.\n  keys: [],\n  // Whether to sort the result list, by score\n  shouldSort: true,\n  // Default sort function: sort by ascending score, ascending index\n  sortFn: (a, b) => a.score === b.score ? a.idx < b.idx ? -1 : 1 : a.score < b.score ? -1 : 1\n};\nconst FuzzyOptions = {\n  // Approximately where in the text is the pattern expected to be found?\n  location: 0,\n  // At what point does the match algorithm give up. A threshold of '0.0' requires a perfect match\n  // (of both letters and location), a threshold of '1.0' would match anything.\n  threshold: 0.6,\n  // Determines how close the match must be to the fuzzy location (specified above).\n  // An exact letter match which is 'distance' characters away from the fuzzy location\n  // would score as a complete mismatch. A distance of '0' requires the match be at\n  // the exact location specified, a threshold of '1000' would require a perfect match\n  // to be within 800 characters of the fuzzy location to be found using a 0.8 threshold.\n  distance: 100\n};\nconst AdvancedOptions = {\n  // When `true`, it enables the use of unix-like search commands\n  useExtendedSearch: false,\n  // The get function to use when fetching an object's properties.\n  // The default will search nested paths *ie foo.bar.baz*\n  getFn: get,\n  // When `true`, search will ignore `location` and `distance`, so it won't matter\n  // where in the string the pattern appears.\n  // More info: https://fusejs.io/concepts/scoring-theory.html#fuzziness-score\n  ignoreLocation: false,\n  // When `true`, the calculation for the relevance score (used for sorting) will\n  // ignore the field-length norm.\n  // More info: https://fusejs.io/concepts/scoring-theory.html#field-length-norm\n  ignoreFieldNorm: false,\n  // The weight to determine how much field length norm effects scoring.\n  fieldNormWeight: 1\n};\nvar Config = _objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({}, BasicOptions), MatchOptions), FuzzyOptions), AdvancedOptions);\nconst SPACE = /[^ ]+/g;\n\n// Field-length norm: the shorter the field, the higher the weight.\n// Set to 3 decimals to reduce index size.\nfunction norm(weight = 1, mantissa = 3) {\n  const cache = new Map();\n  const m = Math.pow(10, mantissa);\n  return {\n    get(value) {\n      const numTokens = value.match(SPACE).length;\n      if (cache.has(numTokens)) {\n        return cache.get(numTokens);\n      }\n\n      // Default function is 1/sqrt(x), weight makes that variable\n      const norm = 1 / Math.pow(numTokens, 0.5 * weight);\n\n      // In place of `toFixed(mantissa)`, for faster computation\n      const n = parseFloat(Math.round(norm * m) / m);\n      cache.set(numTokens, n);\n      return n;\n    },\n    clear() {\n      cache.clear();\n    }\n  };\n}\nclass FuseIndex {\n  constructor({\n    getFn = Config.getFn,\n    fieldNormWeight = Config.fieldNormWeight\n  } = {}) {\n    this.norm = norm(fieldNormWeight, 3);\n    this.getFn = getFn;\n    this.isCreated = false;\n    this.setIndexRecords();\n  }\n  setSources(docs = []) {\n    this.docs = docs;\n  }\n  setIndexRecords(records = []) {\n    this.records = records;\n  }\n  setKeys(keys = []) {\n    this.keys = keys;\n    this._keysMap = {};\n    keys.forEach((key, idx) => {\n      this._keysMap[key.id] = idx;\n    });\n  }\n  create() {\n    if (this.isCreated || !this.docs.length) {\n      return;\n    }\n    this.isCreated = true;\n\n    // List is Array<String>\n    if (isString(this.docs[0])) {\n      this.docs.forEach((doc, docIndex) => {\n        this._addString(doc, docIndex);\n      });\n    } else {\n      // List is Array<Object>\n      this.docs.forEach((doc, docIndex) => {\n        this._addObject(doc, docIndex);\n      });\n    }\n    this.norm.clear();\n  }\n  // Adds a doc to the end of the index\n  add(doc) {\n    const idx = this.size();\n    if (isString(doc)) {\n      this._addString(doc, idx);\n    } else {\n      this._addObject(doc, idx);\n    }\n  }\n  // Removes the doc at the specified index of the index\n  removeAt(idx) {\n    this.records.splice(idx, 1);\n\n    // Change ref index of every subsquent doc\n    for (let i = idx, len = this.size(); i < len; i += 1) {\n      this.records[i].i -= 1;\n    }\n  }\n  getValueForItemAtKeyId(item, keyId) {\n    return item[this._keysMap[keyId]];\n  }\n  size() {\n    return this.records.length;\n  }\n  _addString(doc, docIndex) {\n    if (!isDefined(doc) || isBlank(doc)) {\n      return;\n    }\n    let record = {\n      v: doc,\n      i: docIndex,\n      n: this.norm.get(doc)\n    };\n    this.records.push(record);\n  }\n  _addObject(doc, docIndex) {\n    let record = {\n      i: docIndex,\n      $: {}\n    };\n\n    // Iterate over every key (i.e, path), and fetch the value at that key\n    this.keys.forEach((key, keyIndex) => {\n      let value = key.getFn ? key.getFn(doc) : this.getFn(doc, key.path);\n      if (!isDefined(value)) {\n        return;\n      }\n      if (isArray(value)) {\n        let subRecords = [];\n        const stack = [{\n          nestedArrIndex: -1,\n          value\n        }];\n        while (stack.length) {\n          const {\n            nestedArrIndex,\n            value\n          } = stack.pop();\n          if (!isDefined(value)) {\n            continue;\n          }\n          if (isString(value) && !isBlank(value)) {\n            let subRecord = {\n              v: value,\n              i: nestedArrIndex,\n              n: this.norm.get(value)\n            };\n            subRecords.push(subRecord);\n          } else if (isArray(value)) {\n            value.forEach((item, k) => {\n              stack.push({\n                nestedArrIndex: k,\n                value: item\n              });\n            });\n          } else ;\n        }\n        record.$[keyIndex] = subRecords;\n      } else if (isString(value) && !isBlank(value)) {\n        let subRecord = {\n          v: value,\n          n: this.norm.get(value)\n        };\n        record.$[keyIndex] = subRecord;\n      }\n    });\n    this.records.push(record);\n  }\n  toJSON() {\n    return {\n      keys: this.keys,\n      records: this.records\n    };\n  }\n}\nfunction createIndex(keys, docs, {\n  getFn = Config.getFn,\n  fieldNormWeight = Config.fieldNormWeight\n} = {}) {\n  const myIndex = new FuseIndex({\n    getFn,\n    fieldNormWeight\n  });\n  myIndex.setKeys(keys.map(createKey));\n  myIndex.setSources(docs);\n  myIndex.create();\n  return myIndex;\n}\nfunction parseIndex(data, {\n  getFn = Config.getFn,\n  fieldNormWeight = Config.fieldNormWeight\n} = {}) {\n  const {\n    keys,\n    records\n  } = data;\n  const myIndex = new FuseIndex({\n    getFn,\n    fieldNormWeight\n  });\n  myIndex.setKeys(keys);\n  myIndex.setIndexRecords(records);\n  return myIndex;\n}\nfunction computeScore$1(pattern, {\n  errors = 0,\n  currentLocation = 0,\n  expectedLocation = 0,\n  distance = Config.distance,\n  ignoreLocation = Config.ignoreLocation\n} = {}) {\n  const accuracy = errors / pattern.length;\n  if (ignoreLocation) {\n    return accuracy;\n  }\n  const proximity = Math.abs(expectedLocation - currentLocation);\n  if (!distance) {\n    // Dodge divide by zero error.\n    return proximity ? 1.0 : accuracy;\n  }\n  return accuracy + proximity / distance;\n}\nfunction convertMaskToIndices(matchmask = [], minMatchCharLength = Config.minMatchCharLength) {\n  let indices = [];\n  let start = -1;\n  let end = -1;\n  let i = 0;\n  for (let len = matchmask.length; i < len; i += 1) {\n    let match = matchmask[i];\n    if (match && start === -1) {\n      start = i;\n    } else if (!match && start !== -1) {\n      end = i - 1;\n      if (end - start + 1 >= minMatchCharLength) {\n        indices.push([start, end]);\n      }\n      start = -1;\n    }\n  }\n\n  // (i-1 - start) + 1 => i - start\n  if (matchmask[i - 1] && i - start >= minMatchCharLength) {\n    indices.push([start, i - 1]);\n  }\n  return indices;\n}\n\n// Machine word size\nconst MAX_BITS = 32;\nfunction search(text, pattern, patternAlphabet, {\n  location = Config.location,\n  distance = Config.distance,\n  threshold = Config.threshold,\n  findAllMatches = Config.findAllMatches,\n  minMatchCharLength = Config.minMatchCharLength,\n  includeMatches = Config.includeMatches,\n  ignoreLocation = Config.ignoreLocation\n} = {}) {\n  if (pattern.length > MAX_BITS) {\n    throw new Error(PATTERN_LENGTH_TOO_LARGE(MAX_BITS));\n  }\n  const patternLen = pattern.length;\n  // Set starting location at beginning text and initialize the alphabet.\n  const textLen = text.length;\n  // Handle the case when location > text.length\n  const expectedLocation = Math.max(0, Math.min(location, textLen));\n  // Highest score beyond which we give up.\n  let currentThreshold = threshold;\n  // Is there a nearby exact match? (speedup)\n  let bestLocation = expectedLocation;\n\n  // Performance: only computer matches when the minMatchCharLength > 1\n  // OR if `includeMatches` is true.\n  const computeMatches = minMatchCharLength > 1 || includeMatches;\n  // A mask of the matches, used for building the indices\n  const matchMask = computeMatches ? Array(textLen) : [];\n  let index;\n\n  // Get all exact matches, here for speed up\n  while ((index = text.indexOf(pattern, bestLocation)) > -1) {\n    let score = computeScore$1(pattern, {\n      currentLocation: index,\n      expectedLocation,\n      distance,\n      ignoreLocation\n    });\n    currentThreshold = Math.min(score, currentThreshold);\n    bestLocation = index + patternLen;\n    if (computeMatches) {\n      let i = 0;\n      while (i < patternLen) {\n        matchMask[index + i] = 1;\n        i += 1;\n      }\n    }\n  }\n\n  // Reset the best location\n  bestLocation = -1;\n  let lastBitArr = [];\n  let finalScore = 1;\n  let binMax = patternLen + textLen;\n  const mask = 1 << patternLen - 1;\n  for (let i = 0; i < patternLen; i += 1) {\n    // Scan for the best match; each iteration allows for one more error.\n    // Run a binary search to determine how far from the match location we can stray\n    // at this error level.\n    let binMin = 0;\n    let binMid = binMax;\n    while (binMin < binMid) {\n      const score = computeScore$1(pattern, {\n        errors: i,\n        currentLocation: expectedLocation + binMid,\n        expectedLocation,\n        distance,\n        ignoreLocation\n      });\n      if (score <= currentThreshold) {\n        binMin = binMid;\n      } else {\n        binMax = binMid;\n      }\n      binMid = Math.floor((binMax - binMin) / 2 + binMin);\n    }\n\n    // Use the result from this iteration as the maximum for the next.\n    binMax = binMid;\n    let start = Math.max(1, expectedLocation - binMid + 1);\n    let finish = findAllMatches ? textLen : Math.min(expectedLocation + binMid, textLen) + patternLen;\n\n    // Initialize the bit array\n    let bitArr = Array(finish + 2);\n    bitArr[finish + 1] = (1 << i) - 1;\n    for (let j = finish; j >= start; j -= 1) {\n      let currentLocation = j - 1;\n      let charMatch = patternAlphabet[text.charAt(currentLocation)];\n      if (computeMatches) {\n        // Speed up: quick bool to int conversion (i.e, `charMatch ? 1 : 0`)\n        matchMask[currentLocation] = +!!charMatch;\n      }\n\n      // First pass: exact match\n      bitArr[j] = (bitArr[j + 1] << 1 | 1) & charMatch;\n\n      // Subsequent passes: fuzzy match\n      if (i) {\n        bitArr[j] |= (lastBitArr[j + 1] | lastBitArr[j]) << 1 | 1 | lastBitArr[j + 1];\n      }\n      if (bitArr[j] & mask) {\n        finalScore = computeScore$1(pattern, {\n          errors: i,\n          currentLocation,\n          expectedLocation,\n          distance,\n          ignoreLocation\n        });\n\n        // This match will almost certainly be better than any existing match.\n        // But check anyway.\n        if (finalScore <= currentThreshold) {\n          // Indeed it is\n          currentThreshold = finalScore;\n          bestLocation = currentLocation;\n\n          // Already passed `loc`, downhill from here on in.\n          if (bestLocation <= expectedLocation) {\n            break;\n          }\n\n          // When passing `bestLocation`, don't exceed our current distance from `expectedLocation`.\n          start = Math.max(1, 2 * expectedLocation - bestLocation);\n        }\n      }\n    }\n\n    // No hope for a (better) match at greater error levels.\n    const score = computeScore$1(pattern, {\n      errors: i + 1,\n      currentLocation: expectedLocation,\n      expectedLocation,\n      distance,\n      ignoreLocation\n    });\n    if (score > currentThreshold) {\n      break;\n    }\n    lastBitArr = bitArr;\n  }\n  const result = {\n    isMatch: bestLocation >= 0,\n    // Count exact matches (those with a score of 0) to be \"almost\" exact\n    score: Math.max(0.001, finalScore)\n  };\n  if (computeMatches) {\n    const indices = convertMaskToIndices(matchMask, minMatchCharLength);\n    if (!indices.length) {\n      result.isMatch = false;\n    } else if (includeMatches) {\n      result.indices = indices;\n    }\n  }\n  return result;\n}\nfunction createPatternAlphabet(pattern) {\n  let mask = {};\n  for (let i = 0, len = pattern.length; i < len; i += 1) {\n    const char = pattern.charAt(i);\n    mask[char] = (mask[char] || 0) | 1 << len - i - 1;\n  }\n  return mask;\n}\nclass BitapSearch {\n  constructor(pattern, {\n    location = Config.location,\n    threshold = Config.threshold,\n    distance = Config.distance,\n    includeMatches = Config.includeMatches,\n    findAllMatches = Config.findAllMatches,\n    minMatchCharLength = Config.minMatchCharLength,\n    isCaseSensitive = Config.isCaseSensitive,\n    ignoreLocation = Config.ignoreLocation\n  } = {}) {\n    this.options = {\n      location,\n      threshold,\n      distance,\n      includeMatches,\n      findAllMatches,\n      minMatchCharLength,\n      isCaseSensitive,\n      ignoreLocation\n    };\n    this.pattern = isCaseSensitive ? pattern : pattern.toLowerCase();\n    this.chunks = [];\n    if (!this.pattern.length) {\n      return;\n    }\n    const addChunk = (pattern, startIndex) => {\n      this.chunks.push({\n        pattern,\n        alphabet: createPatternAlphabet(pattern),\n        startIndex\n      });\n    };\n    const len = this.pattern.length;\n    if (len > MAX_BITS) {\n      let i = 0;\n      const remainder = len % MAX_BITS;\n      const end = len - remainder;\n      while (i < end) {\n        addChunk(this.pattern.substr(i, MAX_BITS), i);\n        i += MAX_BITS;\n      }\n      if (remainder) {\n        const startIndex = len - MAX_BITS;\n        addChunk(this.pattern.substr(startIndex), startIndex);\n      }\n    } else {\n      addChunk(this.pattern, 0);\n    }\n  }\n  searchIn(text) {\n    const {\n      isCaseSensitive,\n      includeMatches\n    } = this.options;\n    if (!isCaseSensitive) {\n      text = text.toLowerCase();\n    }\n\n    // Exact match\n    if (this.pattern === text) {\n      let result = {\n        isMatch: true,\n        score: 0\n      };\n      if (includeMatches) {\n        result.indices = [[0, text.length - 1]];\n      }\n      return result;\n    }\n\n    // Otherwise, use Bitap algorithm\n    const {\n      location,\n      distance,\n      threshold,\n      findAllMatches,\n      minMatchCharLength,\n      ignoreLocation\n    } = this.options;\n    let allIndices = [];\n    let totalScore = 0;\n    let hasMatches = false;\n    this.chunks.forEach(({\n      pattern,\n      alphabet,\n      startIndex\n    }) => {\n      const {\n        isMatch,\n        score,\n        indices\n      } = search(text, pattern, alphabet, {\n        location: location + startIndex,\n        distance,\n        threshold,\n        findAllMatches,\n        minMatchCharLength,\n        includeMatches,\n        ignoreLocation\n      });\n      if (isMatch) {\n        hasMatches = true;\n      }\n      totalScore += score;\n      if (isMatch && indices) {\n        allIndices = [...allIndices, ...indices];\n      }\n    });\n    let result = {\n      isMatch: hasMatches,\n      score: hasMatches ? totalScore / this.chunks.length : 1\n    };\n    if (hasMatches && includeMatches) {\n      result.indices = allIndices;\n    }\n    return result;\n  }\n}\nclass BaseMatch {\n  constructor(pattern) {\n    this.pattern = pattern;\n  }\n  static isMultiMatch(pattern) {\n    return getMatch(pattern, this.multiRegex);\n  }\n  static isSingleMatch(pattern) {\n    return getMatch(pattern, this.singleRegex);\n  }\n  search( /*text*/) {}\n}\nfunction getMatch(pattern, exp) {\n  const matches = pattern.match(exp);\n  return matches ? matches[1] : null;\n}\n\n// Token: 'file\n\nclass ExactMatch extends BaseMatch {\n  constructor(pattern) {\n    super(pattern);\n  }\n  static get type() {\n    return 'exact';\n  }\n  static get multiRegex() {\n    return /^=\"(.*)\"$/;\n  }\n  static get singleRegex() {\n    return /^=(.*)$/;\n  }\n  search(text) {\n    const isMatch = text === this.pattern;\n    return {\n      isMatch,\n      score: isMatch ? 0 : 1,\n      indices: [0, this.pattern.length - 1]\n    };\n  }\n}\n\n// Token: !fire\n\nclass InverseExactMatch extends BaseMatch {\n  constructor(pattern) {\n    super(pattern);\n  }\n  static get type() {\n    return 'inverse-exact';\n  }\n  static get multiRegex() {\n    return /^!\"(.*)\"$/;\n  }\n  static get singleRegex() {\n    return /^!(.*)$/;\n  }\n  search(text) {\n    const index = text.indexOf(this.pattern);\n    const isMatch = index === -1;\n    return {\n      isMatch,\n      score: isMatch ? 0 : 1,\n      indices: [0, text.length - 1]\n    };\n  }\n}\n\n// Token: ^file\n\nclass PrefixExactMatch extends BaseMatch {\n  constructor(pattern) {\n    super(pattern);\n  }\n  static get type() {\n    return 'prefix-exact';\n  }\n  static get multiRegex() {\n    return /^\\^\"(.*)\"$/;\n  }\n  static get singleRegex() {\n    return /^\\^(.*)$/;\n  }\n  search(text) {\n    const isMatch = text.startsWith(this.pattern);\n    return {\n      isMatch,\n      score: isMatch ? 0 : 1,\n      indices: [0, this.pattern.length - 1]\n    };\n  }\n}\n\n// Token: !^fire\n\nclass InversePrefixExactMatch extends BaseMatch {\n  constructor(pattern) {\n    super(pattern);\n  }\n  static get type() {\n    return 'inverse-prefix-exact';\n  }\n  static get multiRegex() {\n    return /^!\\^\"(.*)\"$/;\n  }\n  static get singleRegex() {\n    return /^!\\^(.*)$/;\n  }\n  search(text) {\n    const isMatch = !text.startsWith(this.pattern);\n    return {\n      isMatch,\n      score: isMatch ? 0 : 1,\n      indices: [0, text.length - 1]\n    };\n  }\n}\n\n// Token: .file$\n\nclass SuffixExactMatch extends BaseMatch {\n  constructor(pattern) {\n    super(pattern);\n  }\n  static get type() {\n    return 'suffix-exact';\n  }\n  static get multiRegex() {\n    return /^\"(.*)\"\\$$/;\n  }\n  static get singleRegex() {\n    return /^(.*)\\$$/;\n  }\n  search(text) {\n    const isMatch = text.endsWith(this.pattern);\n    return {\n      isMatch,\n      score: isMatch ? 0 : 1,\n      indices: [text.length - this.pattern.length, text.length - 1]\n    };\n  }\n}\n\n// Token: !.file$\n\nclass InverseSuffixExactMatch extends BaseMatch {\n  constructor(pattern) {\n    super(pattern);\n  }\n  static get type() {\n    return 'inverse-suffix-exact';\n  }\n  static get multiRegex() {\n    return /^!\"(.*)\"\\$$/;\n  }\n  static get singleRegex() {\n    return /^!(.*)\\$$/;\n  }\n  search(text) {\n    const isMatch = !text.endsWith(this.pattern);\n    return {\n      isMatch,\n      score: isMatch ? 0 : 1,\n      indices: [0, text.length - 1]\n    };\n  }\n}\nclass FuzzyMatch extends BaseMatch {\n  constructor(pattern, {\n    location = Config.location,\n    threshold = Config.threshold,\n    distance = Config.distance,\n    includeMatches = Config.includeMatches,\n    findAllMatches = Config.findAllMatches,\n    minMatchCharLength = Config.minMatchCharLength,\n    isCaseSensitive = Config.isCaseSensitive,\n    ignoreLocation = Config.ignoreLocation\n  } = {}) {\n    super(pattern);\n    this._bitapSearch = new BitapSearch(pattern, {\n      location,\n      threshold,\n      distance,\n      includeMatches,\n      findAllMatches,\n      minMatchCharLength,\n      isCaseSensitive,\n      ignoreLocation\n    });\n  }\n  static get type() {\n    return 'fuzzy';\n  }\n  static get multiRegex() {\n    return /^\"(.*)\"$/;\n  }\n  static get singleRegex() {\n    return /^(.*)$/;\n  }\n  search(text) {\n    return this._bitapSearch.searchIn(text);\n  }\n}\n\n// Token: 'file\n\nclass IncludeMatch extends BaseMatch {\n  constructor(pattern) {\n    super(pattern);\n  }\n  static get type() {\n    return 'include';\n  }\n  static get multiRegex() {\n    return /^'\"(.*)\"$/;\n  }\n  static get singleRegex() {\n    return /^'(.*)$/;\n  }\n  search(text) {\n    let location = 0;\n    let index;\n    const indices = [];\n    const patternLen = this.pattern.length;\n\n    // Get all exact matches\n    while ((index = text.indexOf(this.pattern, location)) > -1) {\n      location = index + patternLen;\n      indices.push([index, location - 1]);\n    }\n    const isMatch = !!indices.length;\n    return {\n      isMatch,\n      score: isMatch ? 0 : 1,\n      indices\n    };\n  }\n}\n\n// ❗Order is important. DO NOT CHANGE.\nconst searchers = [ExactMatch, IncludeMatch, PrefixExactMatch, InversePrefixExactMatch, InverseSuffixExactMatch, SuffixExactMatch, InverseExactMatch, FuzzyMatch];\nconst searchersLen = searchers.length;\n\n// Regex to split by spaces, but keep anything in quotes together\nconst SPACE_RE = / +(?=(?:[^\\\"]*\\\"[^\\\"]*\\\")*[^\\\"]*$)/;\nconst OR_TOKEN = '|';\n\n// Return a 2D array representation of the query, for simpler parsing.\n// Example:\n// \"^core go$ | rb$ | py$ xy$\" => [[\"^core\", \"go$\"], [\"rb$\"], [\"py$\", \"xy$\"]]\nfunction parseQuery(pattern, options = {}) {\n  return pattern.split(OR_TOKEN).map(item => {\n    let query = item.trim().split(SPACE_RE).filter(item => item && !!item.trim());\n    let results = [];\n    for (let i = 0, len = query.length; i < len; i += 1) {\n      const queryItem = query[i];\n\n      // 1. Handle multiple query match (i.e, once that are quoted, like `\"hello world\"`)\n      let found = false;\n      let idx = -1;\n      while (!found && ++idx < searchersLen) {\n        const searcher = searchers[idx];\n        let token = searcher.isMultiMatch(queryItem);\n        if (token) {\n          results.push(new searcher(token, options));\n          found = true;\n        }\n      }\n      if (found) {\n        continue;\n      }\n\n      // 2. Handle single query matches (i.e, once that are *not* quoted)\n      idx = -1;\n      while (++idx < searchersLen) {\n        const searcher = searchers[idx];\n        let token = searcher.isSingleMatch(queryItem);\n        if (token) {\n          results.push(new searcher(token, options));\n          break;\n        }\n      }\n    }\n    return results;\n  });\n}\n\n// These extended matchers can return an array of matches, as opposed\n// to a singl match\nconst MultiMatchSet = new Set([FuzzyMatch.type, IncludeMatch.type]);\n\n/**\n * Command-like searching\n * ======================\n *\n * Given multiple search terms delimited by spaces.e.g. `^jscript .python$ ruby !java`,\n * search in a given text.\n *\n * Search syntax:\n *\n * | Token       | Match type                 | Description                            |\n * | ----------- | -------------------------- | -------------------------------------- |\n * | `jscript`   | fuzzy-match                | Items that fuzzy match `jscript`       |\n * | `=scheme`   | exact-match                | Items that are `scheme`                |\n * | `'python`   | include-match              | Items that include `python`            |\n * | `!ruby`     | inverse-exact-match        | Items that do not include `ruby`       |\n * | `^java`     | prefix-exact-match         | Items that start with `java`           |\n * | `!^earlang` | inverse-prefix-exact-match | Items that do not start with `earlang` |\n * | `.js$`      | suffix-exact-match         | Items that end with `.js`              |\n * | `!.go$`     | inverse-suffix-exact-match | Items that do not end with `.go`       |\n *\n * A single pipe character acts as an OR operator. For example, the following\n * query matches entries that start with `core` and end with either`go`, `rb`,\n * or`py`.\n *\n * ```\n * ^core go$ | rb$ | py$\n * ```\n */\nclass ExtendedSearch {\n  constructor(pattern, {\n    isCaseSensitive = Config.isCaseSensitive,\n    includeMatches = Config.includeMatches,\n    minMatchCharLength = Config.minMatchCharLength,\n    ignoreLocation = Config.ignoreLocation,\n    findAllMatches = Config.findAllMatches,\n    location = Config.location,\n    threshold = Config.threshold,\n    distance = Config.distance\n  } = {}) {\n    this.query = null;\n    this.options = {\n      isCaseSensitive,\n      includeMatches,\n      minMatchCharLength,\n      findAllMatches,\n      ignoreLocation,\n      location,\n      threshold,\n      distance\n    };\n    this.pattern = isCaseSensitive ? pattern : pattern.toLowerCase();\n    this.query = parseQuery(this.pattern, this.options);\n  }\n  static condition(_, options) {\n    return options.useExtendedSearch;\n  }\n  searchIn(text) {\n    const query = this.query;\n    if (!query) {\n      return {\n        isMatch: false,\n        score: 1\n      };\n    }\n    const {\n      includeMatches,\n      isCaseSensitive\n    } = this.options;\n    text = isCaseSensitive ? text : text.toLowerCase();\n    let numMatches = 0;\n    let allIndices = [];\n    let totalScore = 0;\n\n    // ORs\n    for (let i = 0, qLen = query.length; i < qLen; i += 1) {\n      const searchers = query[i];\n\n      // Reset indices\n      allIndices.length = 0;\n      numMatches = 0;\n\n      // ANDs\n      for (let j = 0, pLen = searchers.length; j < pLen; j += 1) {\n        const searcher = searchers[j];\n        const {\n          isMatch,\n          indices,\n          score\n        } = searcher.search(text);\n        if (isMatch) {\n          numMatches += 1;\n          totalScore += score;\n          if (includeMatches) {\n            const type = searcher.constructor.type;\n            if (MultiMatchSet.has(type)) {\n              allIndices = [...allIndices, ...indices];\n            } else {\n              allIndices.push(indices);\n            }\n          }\n        } else {\n          totalScore = 0;\n          numMatches = 0;\n          allIndices.length = 0;\n          break;\n        }\n      }\n\n      // OR condition, so if TRUE, return\n      if (numMatches) {\n        let result = {\n          isMatch: true,\n          score: totalScore / numMatches\n        };\n        if (includeMatches) {\n          result.indices = allIndices;\n        }\n        return result;\n      }\n    }\n\n    // Nothing was matched\n    return {\n      isMatch: false,\n      score: 1\n    };\n  }\n}\nconst registeredSearchers = [];\nfunction register(...args) {\n  registeredSearchers.push(...args);\n}\nfunction createSearcher(pattern, options) {\n  for (let i = 0, len = registeredSearchers.length; i < len; i += 1) {\n    let searcherClass = registeredSearchers[i];\n    if (searcherClass.condition(pattern, options)) {\n      return new searcherClass(pattern, options);\n    }\n  }\n  return new BitapSearch(pattern, options);\n}\nconst LogicalOperator = {\n  AND: '$and',\n  OR: '$or'\n};\nconst KeyType = {\n  PATH: '$path',\n  PATTERN: '$val'\n};\nconst isExpression = query => !!(query[LogicalOperator.AND] || query[LogicalOperator.OR]);\nconst isPath = query => !!query[KeyType.PATH];\nconst isLeaf = query => !isArray(query) && isObject(query) && !isExpression(query);\nconst convertToExplicit = query => ({\n  [LogicalOperator.AND]: Object.keys(query).map(key => ({\n    [key]: query[key]\n  }))\n});\n\n// When `auto` is `true`, the parse function will infer and initialize and add\n// the appropriate `Searcher` instance\nfunction parse(query, options, {\n  auto = true\n} = {}) {\n  const next = query => {\n    let keys = Object.keys(query);\n    const isQueryPath = isPath(query);\n    if (!isQueryPath && keys.length > 1 && !isExpression(query)) {\n      return next(convertToExplicit(query));\n    }\n    if (isLeaf(query)) {\n      const key = isQueryPath ? query[KeyType.PATH] : keys[0];\n      const pattern = isQueryPath ? query[KeyType.PATTERN] : query[key];\n      if (!isString(pattern)) {\n        throw new Error(LOGICAL_SEARCH_INVALID_QUERY_FOR_KEY(key));\n      }\n      const obj = {\n        keyId: createKeyId(key),\n        pattern\n      };\n      if (auto) {\n        obj.searcher = createSearcher(pattern, options);\n      }\n      return obj;\n    }\n    let node = {\n      children: [],\n      operator: keys[0]\n    };\n    keys.forEach(key => {\n      const value = query[key];\n      if (isArray(value)) {\n        value.forEach(item => {\n          node.children.push(next(item));\n        });\n      }\n    });\n    return node;\n  };\n  if (!isExpression(query)) {\n    query = convertToExplicit(query);\n  }\n  return next(query);\n}\n\n// Practical scoring function\nfunction computeScore(results, {\n  ignoreFieldNorm = Config.ignoreFieldNorm\n}) {\n  results.forEach(result => {\n    let totalScore = 1;\n    result.matches.forEach(({\n      key,\n      norm,\n      score\n    }) => {\n      const weight = key ? key.weight : null;\n      totalScore *= Math.pow(score === 0 && weight ? Number.EPSILON : score, (weight || 1) * (ignoreFieldNorm ? 1 : norm));\n    });\n    result.score = totalScore;\n  });\n}\nfunction transformMatches(result, data) {\n  const matches = result.matches;\n  data.matches = [];\n  if (!isDefined(matches)) {\n    return;\n  }\n  matches.forEach(match => {\n    if (!isDefined(match.indices) || !match.indices.length) {\n      return;\n    }\n    const {\n      indices,\n      value\n    } = match;\n    let obj = {\n      indices,\n      value\n    };\n    if (match.key) {\n      obj.key = match.key.src;\n    }\n    if (match.idx > -1) {\n      obj.refIndex = match.idx;\n    }\n    data.matches.push(obj);\n  });\n}\nfunction transformScore(result, data) {\n  data.score = result.score;\n}\nfunction format(results, docs, {\n  includeMatches = Config.includeMatches,\n  includeScore = Config.includeScore\n} = {}) {\n  const transformers = [];\n  if (includeMatches) transformers.push(transformMatches);\n  if (includeScore) transformers.push(transformScore);\n  return results.map(result => {\n    const {\n      idx\n    } = result;\n    const data = {\n      item: docs[idx],\n      refIndex: idx\n    };\n    if (transformers.length) {\n      transformers.forEach(transformer => {\n        transformer(result, data);\n      });\n    }\n    return data;\n  });\n}\nclass Fuse {\n  constructor(docs, options = {}, index) {\n    this.options = _objectSpread2(_objectSpread2({}, Config), options);\n    if (this.options.useExtendedSearch && false) ;\n    this._keyStore = new KeyStore(this.options.keys);\n    this.setCollection(docs, index);\n  }\n  setCollection(docs, index) {\n    this._docs = docs;\n    if (index && !(index instanceof FuseIndex)) {\n      throw new Error(INCORRECT_INDEX_TYPE);\n    }\n    this._myIndex = index || createIndex(this.options.keys, this._docs, {\n      getFn: this.options.getFn,\n      fieldNormWeight: this.options.fieldNormWeight\n    });\n  }\n  add(doc) {\n    if (!isDefined(doc)) {\n      return;\n    }\n    this._docs.push(doc);\n    this._myIndex.add(doc);\n  }\n  remove(predicate = ( /* doc, idx */) => false) {\n    const results = [];\n    for (let i = 0, len = this._docs.length; i < len; i += 1) {\n      const doc = this._docs[i];\n      if (predicate(doc, i)) {\n        this.removeAt(i);\n        i -= 1;\n        len -= 1;\n        results.push(doc);\n      }\n    }\n    return results;\n  }\n  removeAt(idx) {\n    this._docs.splice(idx, 1);\n    this._myIndex.removeAt(idx);\n  }\n  getIndex() {\n    return this._myIndex;\n  }\n  search(query, {\n    limit = -1\n  } = {}) {\n    const {\n      includeMatches,\n      includeScore,\n      shouldSort,\n      sortFn,\n      ignoreFieldNorm\n    } = this.options;\n    let results = isString(query) ? isString(this._docs[0]) ? this._searchStringList(query) : this._searchObjectList(query) : this._searchLogical(query);\n    computeScore(results, {\n      ignoreFieldNorm\n    });\n    if (shouldSort) {\n      results.sort(sortFn);\n    }\n    if (isNumber(limit) && limit > -1) {\n      results = results.slice(0, limit);\n    }\n    return format(results, this._docs, {\n      includeMatches,\n      includeScore\n    });\n  }\n  _searchStringList(query) {\n    const searcher = createSearcher(query, this.options);\n    const {\n      records\n    } = this._myIndex;\n    const results = [];\n\n    // Iterate over every string in the index\n    records.forEach(({\n      v: text,\n      i: idx,\n      n: norm\n    }) => {\n      if (!isDefined(text)) {\n        return;\n      }\n      const {\n        isMatch,\n        score,\n        indices\n      } = searcher.searchIn(text);\n      if (isMatch) {\n        results.push({\n          item: text,\n          idx,\n          matches: [{\n            score,\n            value: text,\n            norm,\n            indices\n          }]\n        });\n      }\n    });\n    return results;\n  }\n  _searchLogical(query) {\n    const expression = parse(query, this.options);\n    const evaluate = (node, item, idx) => {\n      if (!node.children) {\n        const {\n          keyId,\n          searcher\n        } = node;\n        const matches = this._findMatches({\n          key: this._keyStore.get(keyId),\n          value: this._myIndex.getValueForItemAtKeyId(item, keyId),\n          searcher\n        });\n        if (matches && matches.length) {\n          return [{\n            idx,\n            item,\n            matches\n          }];\n        }\n        return [];\n      }\n      const res = [];\n      for (let i = 0, len = node.children.length; i < len; i += 1) {\n        const child = node.children[i];\n        const result = evaluate(child, item, idx);\n        if (result.length) {\n          res.push(...result);\n        } else if (node.operator === LogicalOperator.AND) {\n          return [];\n        }\n      }\n      return res;\n    };\n    const records = this._myIndex.records;\n    const resultMap = {};\n    const results = [];\n    records.forEach(({\n      $: item,\n      i: idx\n    }) => {\n      if (isDefined(item)) {\n        let expResults = evaluate(expression, item, idx);\n        if (expResults.length) {\n          // Dedupe when adding\n          if (!resultMap[idx]) {\n            resultMap[idx] = {\n              idx,\n              item,\n              matches: []\n            };\n            results.push(resultMap[idx]);\n          }\n          expResults.forEach(({\n            matches\n          }) => {\n            resultMap[idx].matches.push(...matches);\n          });\n        }\n      }\n    });\n    return results;\n  }\n  _searchObjectList(query) {\n    const searcher = createSearcher(query, this.options);\n    const {\n      keys,\n      records\n    } = this._myIndex;\n    const results = [];\n\n    // List is Array<Object>\n    records.forEach(({\n      $: item,\n      i: idx\n    }) => {\n      if (!isDefined(item)) {\n        return;\n      }\n      let matches = [];\n\n      // Iterate over every key (i.e, path), and fetch the value at that key\n      keys.forEach((key, keyIndex) => {\n        matches.push(...this._findMatches({\n          key,\n          value: item[keyIndex],\n          searcher\n        }));\n      });\n      if (matches.length) {\n        results.push({\n          idx,\n          item,\n          matches\n        });\n      }\n    });\n    return results;\n  }\n  _findMatches({\n    key,\n    value,\n    searcher\n  }) {\n    if (!isDefined(value)) {\n      return [];\n    }\n    let matches = [];\n    if (isArray(value)) {\n      value.forEach(({\n        v: text,\n        i: idx,\n        n: norm\n      }) => {\n        if (!isDefined(text)) {\n          return;\n        }\n        const {\n          isMatch,\n          score,\n          indices\n        } = searcher.searchIn(text);\n        if (isMatch) {\n          matches.push({\n            score,\n            key,\n            value: text,\n            idx,\n            norm,\n            indices\n          });\n        }\n      });\n    } else {\n      const {\n        v: text,\n        n: norm\n      } = value;\n      const {\n        isMatch,\n        score,\n        indices\n      } = searcher.searchIn(text);\n      if (isMatch) {\n        matches.push({\n          score,\n          key,\n          value: text,\n          norm,\n          indices\n        });\n      }\n    }\n    return matches;\n  }\n}\nFuse.version = '7.0.0';\nFuse.createIndex = createIndex;\nFuse.parseIndex = parseIndex;\nFuse.config = Config;\n{\n  Fuse.parseQuery = parse;\n}\n{\n  register(ExtendedSearch);\n}\n\nvar SearchByFuse = /** @class */ (function () {\n    function SearchByFuse(config) {\n        this._haystack = [];\n        this._fuseOptions = __assign(__assign({}, config.fuseOptions), { keys: __spreadArray([], config.searchFields, true), includeMatches: true });\n    }\n    SearchByFuse.prototype.index = function (data) {\n        this._haystack = data;\n        if (this._fuse) {\n            this._fuse.setCollection(data);\n        }\n    };\n    SearchByFuse.prototype.reset = function () {\n        this._haystack = [];\n        this._fuse = undefined;\n    };\n    SearchByFuse.prototype.isEmptyIndex = function () {\n        return !this._haystack.length;\n    };\n    SearchByFuse.prototype.search = function (needle) {\n        if (!this._fuse) {\n            {\n                this._fuse = new Fuse(this._haystack, this._fuseOptions);\n            }\n        }\n        var results = this._fuse.search(needle);\n        return results.map(function (value, i) {\n            return {\n                item: value.item,\n                score: value.score || 0,\n                rank: i + 1, // If value.score is used for sorting, this can create non-stable sorts!\n            };\n        });\n    };\n    return SearchByFuse;\n}());\n\nfunction getSearcher(config) {\n    {\n        return new SearchByFuse(config);\n    }\n}\n\n/**\n * Helpers to create HTML elements used by Choices\n * Can be overridden by providing `callbackOnCreateTemplates` option.\n * `Choices.defaults.templates` allows access to the default template methods from `callbackOnCreateTemplates`\n */\nvar isEmptyObject = function (obj) {\n    // eslint-disable-next-line no-restricted-syntax\n    for (var prop in obj) {\n        if (Object.prototype.hasOwnProperty.call(obj, prop)) {\n            return false;\n        }\n    }\n    return true;\n};\nvar assignCustomProperties = function (el, choice, withCustomProperties) {\n    var dataset = el.dataset;\n    var customProperties = choice.customProperties, labelClass = choice.labelClass, labelDescription = choice.labelDescription;\n    if (labelClass) {\n        dataset.labelClass = getClassNames(labelClass).join(' ');\n    }\n    if (labelDescription) {\n        dataset.labelDescription = unwrapStringForRaw(labelDescription);\n    }\n    if (withCustomProperties && customProperties) {\n        if (typeof customProperties === 'string') {\n            dataset.customProperties = customProperties;\n        }\n        else if (typeof customProperties === 'object' && !isEmptyObject(customProperties)) {\n            dataset.customProperties = JSON.stringify(customProperties);\n        }\n    }\n};\nvar addAriaLabel = function (docRoot, id, element) {\n    var label = id && docRoot.querySelector(\"label[for='\".concat(id, \"']\"));\n    var text = label && label.innerText;\n    if (text) {\n        element.setAttribute('aria-label', text);\n    }\n};\nvar templates = {\n    containerOuter: function (_a, dir, isSelectElement, isSelectOneElement, searchEnabled, passedElementType, labelId) {\n        var containerOuter = _a.classNames.containerOuter;\n        var div = document.createElement('div');\n        addClassesToElement(div, containerOuter);\n        div.dataset.type = passedElementType;\n        if (dir) {\n            div.dir = dir;\n        }\n        if (isSelectOneElement) {\n            div.tabIndex = 0;\n        }\n        if (isSelectElement) {\n            div.setAttribute('role', searchEnabled ? 'combobox' : 'listbox');\n            if (searchEnabled) {\n                div.setAttribute('aria-autocomplete', 'list');\n            }\n            else if (!labelId) {\n                addAriaLabel(this._docRoot, this.passedElement.element.id, div);\n            }\n            div.setAttribute('aria-haspopup', 'true');\n            div.setAttribute('aria-expanded', 'false');\n        }\n        if (labelId) {\n            div.setAttribute('aria-labelledby', labelId);\n        }\n        return div;\n    },\n    containerInner: function (_a) {\n        var containerInner = _a.classNames.containerInner;\n        var div = document.createElement('div');\n        addClassesToElement(div, containerInner);\n        return div;\n    },\n    itemList: function (_a, isSelectOneElement) {\n        var searchEnabled = _a.searchEnabled, _b = _a.classNames, list = _b.list, listSingle = _b.listSingle, listItems = _b.listItems;\n        var div = document.createElement('div');\n        addClassesToElement(div, list);\n        addClassesToElement(div, isSelectOneElement ? listSingle : listItems);\n        if (this._isSelectElement && searchEnabled) {\n            div.setAttribute('role', 'listbox');\n        }\n        return div;\n    },\n    placeholder: function (_a, value) {\n        var allowHTML = _a.allowHTML, placeholder = _a.classNames.placeholder;\n        var div = document.createElement('div');\n        addClassesToElement(div, placeholder);\n        setElementHtml(div, allowHTML, value);\n        return div;\n    },\n    item: function (_a, choice, removeItemButton) {\n        var allowHTML = _a.allowHTML, removeItemButtonAlignLeft = _a.removeItemButtonAlignLeft, removeItemIconText = _a.removeItemIconText, removeItemLabelText = _a.removeItemLabelText, _b = _a.classNames, item = _b.item, button = _b.button, highlightedState = _b.highlightedState, itemSelectable = _b.itemSelectable, placeholder = _b.placeholder;\n        var rawValue = unwrapStringForRaw(choice.value);\n        var div = document.createElement('div');\n        addClassesToElement(div, item);\n        if (choice.labelClass) {\n            var spanLabel = document.createElement('span');\n            setElementHtml(spanLabel, allowHTML, choice.label);\n            addClassesToElement(spanLabel, choice.labelClass);\n            div.appendChild(spanLabel);\n        }\n        else {\n            setElementHtml(div, allowHTML, choice.label);\n        }\n        div.dataset.item = '';\n        div.dataset.id = choice.id;\n        div.dataset.value = rawValue;\n        assignCustomProperties(div, choice, true);\n        if (choice.disabled || this.containerOuter.isDisabled) {\n            div.setAttribute('aria-disabled', 'true');\n        }\n        if (this._isSelectElement) {\n            div.setAttribute('aria-selected', 'true');\n            div.setAttribute('role', 'option');\n        }\n        if (choice.placeholder) {\n            addClassesToElement(div, placeholder);\n            div.dataset.placeholder = '';\n        }\n        addClassesToElement(div, choice.highlighted ? highlightedState : itemSelectable);\n        if (removeItemButton) {\n            if (choice.disabled) {\n                removeClassesFromElement(div, itemSelectable);\n            }\n            div.dataset.deletable = '';\n            var removeButton = document.createElement('button');\n            removeButton.type = 'button';\n            addClassesToElement(removeButton, button);\n            var eventChoice = getChoiceForOutput(choice);\n            setElementHtml(removeButton, true, resolveNoticeFunction(removeItemIconText, choice.value, eventChoice));\n            var REMOVE_ITEM_LABEL = resolveNoticeFunction(removeItemLabelText, choice.value, eventChoice);\n            if (REMOVE_ITEM_LABEL) {\n                removeButton.setAttribute('aria-label', REMOVE_ITEM_LABEL);\n            }\n            removeButton.dataset.button = '';\n            if (removeItemButtonAlignLeft) {\n                div.insertAdjacentElement('afterbegin', removeButton);\n            }\n            else {\n                div.appendChild(removeButton);\n            }\n        }\n        return div;\n    },\n    choiceList: function (_a, isSelectOneElement) {\n        var list = _a.classNames.list;\n        var div = document.createElement('div');\n        addClassesToElement(div, list);\n        if (!isSelectOneElement) {\n            div.setAttribute('aria-multiselectable', 'true');\n        }\n        div.setAttribute('role', 'listbox');\n        return div;\n    },\n    choiceGroup: function (_a, _b) {\n        var allowHTML = _a.allowHTML, _c = _a.classNames, group = _c.group, groupHeading = _c.groupHeading, itemDisabled = _c.itemDisabled;\n        var id = _b.id, label = _b.label, disabled = _b.disabled;\n        var rawLabel = unwrapStringForRaw(label);\n        var div = document.createElement('div');\n        addClassesToElement(div, group);\n        if (disabled) {\n            addClassesToElement(div, itemDisabled);\n        }\n        div.setAttribute('role', 'group');\n        div.dataset.group = '';\n        div.dataset.id = id;\n        div.dataset.value = rawLabel;\n        if (disabled) {\n            div.setAttribute('aria-disabled', 'true');\n        }\n        var heading = document.createElement('div');\n        addClassesToElement(heading, groupHeading);\n        setElementHtml(heading, allowHTML, label || '');\n        div.appendChild(heading);\n        return div;\n    },\n    choice: function (_a, choice, selectText, groupName) {\n        var allowHTML = _a.allowHTML, _b = _a.classNames, item = _b.item, itemChoice = _b.itemChoice, itemSelectable = _b.itemSelectable, selectedState = _b.selectedState, itemDisabled = _b.itemDisabled, description = _b.description, placeholder = _b.placeholder;\n        // eslint-disable-next-line prefer-destructuring\n        var label = choice.label;\n        var rawValue = unwrapStringForRaw(choice.value);\n        var div = document.createElement('div');\n        div.id = choice.elementId;\n        addClassesToElement(div, item);\n        addClassesToElement(div, itemChoice);\n        if (groupName && typeof label === 'string') {\n            label = escapeForTemplate(allowHTML, label);\n            label += \" (\".concat(groupName, \")\");\n            label = { trusted: label };\n        }\n        var describedBy = div;\n        if (choice.labelClass) {\n            var spanLabel = document.createElement('span');\n            setElementHtml(spanLabel, allowHTML, label);\n            addClassesToElement(spanLabel, choice.labelClass);\n            describedBy = spanLabel;\n            div.appendChild(spanLabel);\n        }\n        else {\n            setElementHtml(div, allowHTML, label);\n        }\n        if (choice.labelDescription) {\n            var descId = \"\".concat(choice.elementId, \"-description\");\n            describedBy.setAttribute('aria-describedby', descId);\n            var spanDesc = document.createElement('span');\n            setElementHtml(spanDesc, allowHTML, choice.labelDescription);\n            spanDesc.id = descId;\n            addClassesToElement(spanDesc, description);\n            div.appendChild(spanDesc);\n        }\n        if (choice.selected) {\n            addClassesToElement(div, selectedState);\n        }\n        if (choice.placeholder) {\n            addClassesToElement(div, placeholder);\n        }\n        div.setAttribute('role', choice.group ? 'treeitem' : 'option');\n        div.dataset.choice = '';\n        div.dataset.id = choice.id;\n        div.dataset.value = rawValue;\n        if (selectText) {\n            div.dataset.selectText = selectText;\n        }\n        if (choice.group) {\n            div.dataset.groupId = \"\".concat(choice.group.id);\n        }\n        assignCustomProperties(div, choice, false);\n        if (choice.disabled) {\n            addClassesToElement(div, itemDisabled);\n            div.dataset.choiceDisabled = '';\n            div.setAttribute('aria-disabled', 'true');\n        }\n        else {\n            addClassesToElement(div, itemSelectable);\n            div.dataset.choiceSelectable = '';\n            div.setAttribute('aria-selected', choice.selected ? 'true' : 'false');\n        }\n        return div;\n    },\n    input: function (_a, placeholderValue) {\n        var _b = _a.classNames, input = _b.input, inputCloned = _b.inputCloned, labelId = _a.labelId;\n        var inp = document.createElement('input');\n        inp.type = 'search';\n        addClassesToElement(inp, input);\n        addClassesToElement(inp, inputCloned);\n        inp.autocomplete = 'off';\n        inp.autocapitalize = 'off';\n        inp.spellcheck = false;\n        inp.setAttribute('aria-autocomplete', 'list');\n        if (placeholderValue) {\n            inp.setAttribute('aria-label', placeholderValue);\n        }\n        else if (!labelId) {\n            addAriaLabel(this._docRoot, this.passedElement.element.id, inp);\n        }\n        return inp;\n    },\n    dropdown: function (_a) {\n        var _b = _a.classNames, list = _b.list, listDropdown = _b.listDropdown;\n        var div = document.createElement('div');\n        addClassesToElement(div, list);\n        addClassesToElement(div, listDropdown);\n        div.setAttribute('aria-expanded', 'false');\n        return div;\n    },\n    notice: function (_a, innerHTML, type) {\n        var _b = _a.classNames, item = _b.item, itemChoice = _b.itemChoice, addChoice = _b.addChoice, noResults = _b.noResults, noChoices = _b.noChoices, noticeItem = _b.notice;\n        if (type === void 0) { type = NoticeTypes.generic; }\n        var notice = document.createElement('div');\n        setElementHtml(notice, true, innerHTML);\n        addClassesToElement(notice, item);\n        addClassesToElement(notice, itemChoice);\n        addClassesToElement(notice, noticeItem);\n        // eslint-disable-next-line default-case\n        switch (type) {\n            case NoticeTypes.addChoice:\n                addClassesToElement(notice, addChoice);\n                break;\n            case NoticeTypes.noResults:\n                addClassesToElement(notice, noResults);\n                break;\n            case NoticeTypes.noChoices:\n                addClassesToElement(notice, noChoices);\n                break;\n        }\n        if (type === NoticeTypes.addChoice) {\n            notice.dataset.choiceSelectable = '';\n            notice.dataset.choice = '';\n        }\n        return notice;\n    },\n    option: function (choice) {\n        // HtmlOptionElement's label value does not support HTML, so the avoid double escaping unwrap the untrusted string.\n        var labelValue = unwrapStringForRaw(choice.label);\n        var opt = new Option(labelValue, choice.value, false, choice.selected);\n        assignCustomProperties(opt, choice, true);\n        opt.disabled = choice.disabled;\n        if (choice.selected) {\n            opt.setAttribute('selected', '');\n        }\n        return opt;\n    },\n};\n\n/** @see {@link http://browserhacks.com/#hack-acea075d0ac6954f275a70023906050c} */\nvar IS_IE11 = '-ms-scroll-limit' in document.documentElement.style &&\n    '-ms-ime-align' in document.documentElement.style;\nvar USER_DEFAULTS = {};\nvar parseDataSetId = function (element) {\n    if (!element) {\n        return undefined;\n    }\n    return element.dataset.id ? parseInt(element.dataset.id, 10) : undefined;\n};\nvar selectableChoiceIdentifier = '[data-choice-selectable]';\n/**\n * Choices\n * @author Josh Johnson<josh@joshuajohnson.co.uk>\n */\nvar Choices = /** @class */ (function () {\n    function Choices(element, userConfig) {\n        if (element === void 0) { element = '[data-choice]'; }\n        if (userConfig === void 0) { userConfig = {}; }\n        var _this = this;\n        this.initialisedOK = undefined;\n        this._hasNonChoicePlaceholder = false;\n        this._lastAddedChoiceId = 0;\n        this._lastAddedGroupId = 0;\n        var defaults = Choices.defaults;\n        this.config = __assign(__assign(__assign({}, defaults.allOptions), defaults.options), userConfig);\n        ObjectsInConfig.forEach(function (key) {\n            _this.config[key] = __assign(__assign(__assign({}, defaults.allOptions[key]), defaults.options[key]), userConfig[key]);\n        });\n        var config = this.config;\n        if (!config.silent) {\n            this._validateConfig();\n        }\n        var docRoot = config.shadowRoot || document.documentElement;\n        this._docRoot = docRoot;\n        var passedElement = typeof element === 'string' ? docRoot.querySelector(element) : element;\n        if (!passedElement ||\n            typeof passedElement !== 'object' ||\n            !(isHtmlInputElement(passedElement) || isHtmlSelectElement(passedElement))) {\n            if (!passedElement && typeof element === 'string') {\n                throw TypeError(\"Selector \".concat(element, \" failed to find an element\"));\n            }\n            throw TypeError(\"Expected one of the following types text|select-one|select-multiple\");\n        }\n        var elementType = passedElement.type;\n        var isText = elementType === PassedElementTypes.Text;\n        if (isText || config.maxItemCount !== 1) {\n            config.singleModeForMultiSelect = false;\n        }\n        if (config.singleModeForMultiSelect) {\n            elementType = PassedElementTypes.SelectMultiple;\n        }\n        var isSelectOne = elementType === PassedElementTypes.SelectOne;\n        var isSelectMultiple = elementType === PassedElementTypes.SelectMultiple;\n        var isSelect = isSelectOne || isSelectMultiple;\n        this._elementType = elementType;\n        this._isTextElement = isText;\n        this._isSelectOneElement = isSelectOne;\n        this._isSelectMultipleElement = isSelectMultiple;\n        this._isSelectElement = isSelectOne || isSelectMultiple;\n        this._canAddUserChoices = (isText && config.addItems) || (isSelect && config.addChoices);\n        if (typeof config.renderSelectedChoices !== 'boolean') {\n            config.renderSelectedChoices = config.renderSelectedChoices === 'always' || isSelectOne;\n        }\n        if (config.closeDropdownOnSelect === 'auto') {\n            config.closeDropdownOnSelect = isText || isSelectOne || config.singleModeForMultiSelect;\n        }\n        else {\n            config.closeDropdownOnSelect = coerceBool(config.closeDropdownOnSelect);\n        }\n        if (config.placeholder) {\n            if (config.placeholderValue) {\n                this._hasNonChoicePlaceholder = true;\n            }\n            else if (passedElement.dataset.placeholder) {\n                this._hasNonChoicePlaceholder = true;\n                config.placeholderValue = passedElement.dataset.placeholder;\n            }\n        }\n        if (userConfig.addItemFilter && typeof userConfig.addItemFilter !== 'function') {\n            var re = userConfig.addItemFilter instanceof RegExp ? userConfig.addItemFilter : new RegExp(userConfig.addItemFilter);\n            config.addItemFilter = re.test.bind(re);\n        }\n        if (this._isTextElement) {\n            this.passedElement = new WrappedInput({\n                element: passedElement,\n                classNames: config.classNames,\n            });\n        }\n        else {\n            var selectEl = passedElement;\n            this.passedElement = new WrappedSelect({\n                element: selectEl,\n                classNames: config.classNames,\n                template: function (data) { return _this._templates.option(data); },\n                extractPlaceholder: config.placeholder && !this._hasNonChoicePlaceholder,\n            });\n        }\n        this.initialised = false;\n        this._store = new Store(config);\n        this._currentValue = '';\n        config.searchEnabled = !isText && config.searchEnabled;\n        this._canSearch = config.searchEnabled;\n        this._isScrollingOnIe = false;\n        this._highlightPosition = 0;\n        this._wasTap = true;\n        this._placeholderValue = this._generatePlaceholderValue();\n        this._baseId = generateId(passedElement, 'choices-');\n        /**\n         * setting direction in cases where it's explicitly set on passedElement\n         * or when calculated direction is different from the document\n         */\n        this._direction = passedElement.dir;\n        if (!this._direction) {\n            var elementDirection = window.getComputedStyle(passedElement).direction;\n            var documentDirection = window.getComputedStyle(document.documentElement).direction;\n            if (elementDirection !== documentDirection) {\n                this._direction = elementDirection;\n            }\n        }\n        this._idNames = {\n            itemChoice: 'item-choice',\n        };\n        this._templates = defaults.templates;\n        this._render = this._render.bind(this);\n        this._onFocus = this._onFocus.bind(this);\n        this._onBlur = this._onBlur.bind(this);\n        this._onKeyUp = this._onKeyUp.bind(this);\n        this._onKeyDown = this._onKeyDown.bind(this);\n        this._onInput = this._onInput.bind(this);\n        this._onClick = this._onClick.bind(this);\n        this._onTouchMove = this._onTouchMove.bind(this);\n        this._onTouchEnd = this._onTouchEnd.bind(this);\n        this._onMouseDown = this._onMouseDown.bind(this);\n        this._onMouseOver = this._onMouseOver.bind(this);\n        this._onFormReset = this._onFormReset.bind(this);\n        this._onSelectKey = this._onSelectKey.bind(this);\n        this._onEnterKey = this._onEnterKey.bind(this);\n        this._onEscapeKey = this._onEscapeKey.bind(this);\n        this._onDirectionKey = this._onDirectionKey.bind(this);\n        this._onDeleteKey = this._onDeleteKey.bind(this);\n        this._onChange = this._onChange.bind(this);\n        this._onInvalid = this._onInvalid.bind(this);\n        // If element has already been initialised with Choices, fail silently\n        if (this.passedElement.isActive) {\n            if (!config.silent) {\n                console.warn('Trying to initialise Choices on element already initialised', { element: element });\n            }\n            this.initialised = true;\n            this.initialisedOK = false;\n            return;\n        }\n        // Let's go\n        this.init();\n        // preserve the selected item list after setup for form reset\n        this._initialItems = this._store.items.map(function (choice) { return choice.value; });\n    }\n    Object.defineProperty(Choices, \"defaults\", {\n        get: function () {\n            return Object.preventExtensions({\n                get options() {\n                    return USER_DEFAULTS;\n                },\n                get allOptions() {\n                    return DEFAULT_CONFIG;\n                },\n                get templates() {\n                    return templates;\n                },\n            });\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Choices.prototype.init = function () {\n        if (this.initialised || this.initialisedOK !== undefined) {\n            return;\n        }\n        this._searcher = getSearcher(this.config);\n        this._loadChoices();\n        this._createTemplates();\n        this._createElements();\n        this._createStructure();\n        if ((this._isTextElement && !this.config.addItems) ||\n            this.passedElement.element.hasAttribute('disabled') ||\n            !!this.passedElement.element.closest('fieldset:disabled')) {\n            this.disable();\n        }\n        else {\n            this.enable();\n            this._addEventListeners();\n        }\n        // should be triggered **after** disabled state to avoid additional re-draws\n        this._initStore();\n        this.initialised = true;\n        this.initialisedOK = true;\n        var callbackOnInit = this.config.callbackOnInit;\n        // Run callback if it is a function\n        if (typeof callbackOnInit === 'function') {\n            callbackOnInit.call(this);\n        }\n    };\n    Choices.prototype.destroy = function () {\n        if (!this.initialised) {\n            return;\n        }\n        this._removeEventListeners();\n        this.passedElement.reveal();\n        this.containerOuter.unwrap(this.passedElement.element);\n        this._store._listeners = []; // prevents select/input value being wiped\n        this.clearStore(false);\n        this._stopSearch();\n        this._templates = Choices.defaults.templates;\n        this.initialised = false;\n        this.initialisedOK = undefined;\n    };\n    Choices.prototype.enable = function () {\n        if (this.passedElement.isDisabled) {\n            this.passedElement.enable();\n        }\n        if (this.containerOuter.isDisabled) {\n            this._addEventListeners();\n            this.input.enable();\n            this.containerOuter.enable();\n        }\n        return this;\n    };\n    Choices.prototype.disable = function () {\n        if (!this.passedElement.isDisabled) {\n            this.passedElement.disable();\n        }\n        if (!this.containerOuter.isDisabled) {\n            this._removeEventListeners();\n            this.input.disable();\n            this.containerOuter.disable();\n        }\n        return this;\n    };\n    Choices.prototype.highlightItem = function (item, runEvent) {\n        if (runEvent === void 0) { runEvent = true; }\n        if (!item || !item.id) {\n            return this;\n        }\n        var choice = this._store.items.find(function (c) { return c.id === item.id; });\n        if (!choice || choice.highlighted) {\n            return this;\n        }\n        this._store.dispatch(highlightItem(choice, true));\n        if (runEvent) {\n            this.passedElement.triggerEvent(EventType.highlightItem, getChoiceForOutput(choice));\n        }\n        return this;\n    };\n    Choices.prototype.unhighlightItem = function (item, runEvent) {\n        if (runEvent === void 0) { runEvent = true; }\n        if (!item || !item.id) {\n            return this;\n        }\n        var choice = this._store.items.find(function (c) { return c.id === item.id; });\n        if (!choice || !choice.highlighted) {\n            return this;\n        }\n        this._store.dispatch(highlightItem(choice, false));\n        if (runEvent) {\n            this.passedElement.triggerEvent(EventType.unhighlightItem, getChoiceForOutput(choice));\n        }\n        return this;\n    };\n    Choices.prototype.highlightAll = function () {\n        var _this = this;\n        this._store.withTxn(function () {\n            _this._store.items.forEach(function (item) {\n                if (!item.highlighted) {\n                    _this._store.dispatch(highlightItem(item, true));\n                    _this.passedElement.triggerEvent(EventType.highlightItem, getChoiceForOutput(item));\n                }\n            });\n        });\n        return this;\n    };\n    Choices.prototype.unhighlightAll = function () {\n        var _this = this;\n        this._store.withTxn(function () {\n            _this._store.items.forEach(function (item) {\n                if (item.highlighted) {\n                    _this._store.dispatch(highlightItem(item, false));\n                    _this.passedElement.triggerEvent(EventType.highlightItem, getChoiceForOutput(item));\n                }\n            });\n        });\n        return this;\n    };\n    Choices.prototype.removeActiveItemsByValue = function (value) {\n        var _this = this;\n        this._store.withTxn(function () {\n            _this._store.items.filter(function (item) { return item.value === value; }).forEach(function (item) { return _this._removeItem(item); });\n        });\n        return this;\n    };\n    Choices.prototype.removeActiveItems = function (excludedId) {\n        var _this = this;\n        this._store.withTxn(function () {\n            _this._store.items.filter(function (_a) {\n                var id = _a.id;\n                return id !== excludedId;\n            }).forEach(function (item) { return _this._removeItem(item); });\n        });\n        return this;\n    };\n    Choices.prototype.removeHighlightedItems = function (runEvent) {\n        var _this = this;\n        if (runEvent === void 0) { runEvent = false; }\n        this._store.withTxn(function () {\n            _this._store.highlightedActiveItems.forEach(function (item) {\n                _this._removeItem(item);\n                // If this action was performed by the user\n                // trigger the event\n                if (runEvent) {\n                    _this._triggerChange(item.value);\n                }\n            });\n        });\n        return this;\n    };\n    Choices.prototype.showDropdown = function (preventInputFocus) {\n        var _this = this;\n        if (this.dropdown.isActive) {\n            return this;\n        }\n        if (preventInputFocus === undefined) {\n            // eslint-disable-next-line no-param-reassign\n            preventInputFocus = !this._canSearch;\n        }\n        requestAnimationFrame(function () {\n            _this.dropdown.show();\n            var rect = _this.dropdown.element.getBoundingClientRect();\n            _this.containerOuter.open(rect.bottom, rect.height);\n            if (!preventInputFocus) {\n                _this.input.focus();\n            }\n            _this.passedElement.triggerEvent(EventType.showDropdown);\n            var activeElement = _this.choiceList.element.querySelector(getClassNamesSelector(_this.config.classNames.selectedState));\n            if (activeElement !== null && !isScrolledIntoView(activeElement, _this.choiceList.element)) {\n                // We use the native scrollIntoView function instead of choiceList.scrollToChildElement to avoid animated scroll.\n                activeElement.scrollIntoView();\n            }\n        });\n        return this;\n    };\n    Choices.prototype.hideDropdown = function (preventInputBlur) {\n        var _this = this;\n        if (!this.dropdown.isActive) {\n            return this;\n        }\n        this._removeHighlightedChoices();\n        requestAnimationFrame(function () {\n            _this.dropdown.hide();\n            _this.containerOuter.close();\n            if (!preventInputBlur && _this._canSearch) {\n                _this.input.removeActiveDescendant();\n                _this.input.blur();\n            }\n            _this.passedElement.triggerEvent(EventType.hideDropdown);\n        });\n        return this;\n    };\n    Choices.prototype.getValue = function (valueOnly) {\n        var values = this._store.items.map(function (item) {\n            return (valueOnly ? item.value : getChoiceForOutput(item));\n        });\n        return this._isSelectOneElement || this.config.singleModeForMultiSelect ? values[0] : values;\n    };\n    Choices.prototype.setValue = function (items) {\n        var _this = this;\n        if (!this.initialisedOK) {\n            this._warnChoicesInitFailed('setValue');\n            return this;\n        }\n        this._store.withTxn(function () {\n            items.forEach(function (value) {\n                if (value) {\n                    _this._addChoice(mapInputToChoice(value, false));\n                }\n            });\n        });\n        // @todo integrate with Store\n        this._searcher.reset();\n        return this;\n    };\n    Choices.prototype.setChoiceByValue = function (value) {\n        var _this = this;\n        if (!this.initialisedOK) {\n            this._warnChoicesInitFailed('setChoiceByValue');\n            return this;\n        }\n        if (this._isTextElement) {\n            return this;\n        }\n        this._store.withTxn(function () {\n            // If only one value has been passed, convert to array\n            var choiceValue = Array.isArray(value) ? value : [value];\n            // Loop through each value and\n            choiceValue.forEach(function (val) { return _this._findAndSelectChoiceByValue(val); });\n            _this.unhighlightAll();\n        });\n        // @todo integrate with Store\n        this._searcher.reset();\n        return this;\n    };\n    /**\n     * Set choices of select input via an array of objects (or function that returns array of object or promise of it),\n     * a value field name and a label field name.\n     * This behaves the same as passing items via the choices option but can be called after initialising Choices.\n     * This can also be used to add groups of choices (see example 2); Optionally pass a true `replaceChoices` value to remove any existing choices.\n     * Optionally pass a `customProperties` object to add additional data to your choices (useful when searching/filtering etc).\n     *\n     * **Input types affected:** select-one, select-multiple\n     *\n     * @example\n     * ```js\n     * const example = new Choices(element);\n     *\n     * example.setChoices([\n     *   {value: 'One', label: 'Label One', disabled: true},\n     *   {value: 'Two', label: 'Label Two', selected: true},\n     *   {value: 'Three', label: 'Label Three'},\n     * ], 'value', 'label', false);\n     * ```\n     *\n     * @example\n     * ```js\n     * const example = new Choices(element);\n     *\n     * example.setChoices(async () => {\n     *   try {\n     *      const items = await fetch('/items');\n     *      return items.json()\n     *   } catch(err) {\n     *      console.error(err)\n     *   }\n     * });\n     * ```\n     *\n     * @example\n     * ```js\n     * const example = new Choices(element);\n     *\n     * example.setChoices([{\n     *   label: 'Group one',\n     *   id: 1,\n     *   disabled: false,\n     *   choices: [\n     *     {value: 'Child One', label: 'Child One', selected: true},\n     *     {value: 'Child Two', label: 'Child Two',  disabled: true},\n     *     {value: 'Child Three', label: 'Child Three'},\n     *   ]\n     * },\n     * {\n     *   label: 'Group two',\n     *   id: 2,\n     *   disabled: false,\n     *   choices: [\n     *     {value: 'Child Four', label: 'Child Four', disabled: true},\n     *     {value: 'Child Five', label: 'Child Five'},\n     *     {value: 'Child Six', label: 'Child Six', customProperties: {\n     *       description: 'Custom description about child six',\n     *       random: 'Another random custom property'\n     *     }},\n     *   ]\n     * }], 'value', 'label', false);\n     * ```\n     */\n    Choices.prototype.setChoices = function (choicesArrayOrFetcher, value, label, replaceChoices, clearSearchFlag, replaceItems) {\n        var _this = this;\n        if (choicesArrayOrFetcher === void 0) { choicesArrayOrFetcher = []; }\n        if (value === void 0) { value = 'value'; }\n        if (label === void 0) { label = 'label'; }\n        if (replaceChoices === void 0) { replaceChoices = false; }\n        if (clearSearchFlag === void 0) { clearSearchFlag = true; }\n        if (replaceItems === void 0) { replaceItems = false; }\n        if (!this.initialisedOK) {\n            this._warnChoicesInitFailed('setChoices');\n            return this;\n        }\n        if (!this._isSelectElement) {\n            throw new TypeError(\"setChoices can't be used with INPUT based Choices\");\n        }\n        if (typeof value !== 'string' || !value) {\n            throw new TypeError(\"value parameter must be a name of 'value' field in passed objects\");\n        }\n        if (typeof choicesArrayOrFetcher === 'function') {\n            // it's a choices fetcher function\n            var fetcher_1 = choicesArrayOrFetcher(this);\n            if (typeof Promise === 'function' && fetcher_1 instanceof Promise) {\n                // that's a promise\n                // eslint-disable-next-line no-promise-executor-return\n                return new Promise(function (resolve) { return requestAnimationFrame(resolve); })\n                    .then(function () { return _this._handleLoadingState(true); })\n                    .then(function () { return fetcher_1; })\n                    .then(function (data) {\n                    return _this.setChoices(data, value, label, replaceChoices, clearSearchFlag, replaceItems);\n                })\n                    .catch(function (err) {\n                    if (!_this.config.silent) {\n                        console.error(err);\n                    }\n                })\n                    .then(function () { return _this._handleLoadingState(false); })\n                    .then(function () { return _this; });\n            }\n            // function returned something else than promise, let's check if it's an array of choices\n            if (!Array.isArray(fetcher_1)) {\n                throw new TypeError(\".setChoices first argument function must return either array of choices or Promise, got: \".concat(typeof fetcher_1));\n            }\n            // recursion with results, it's sync and choices were cleared already\n            return this.setChoices(fetcher_1, value, label, false);\n        }\n        if (!Array.isArray(choicesArrayOrFetcher)) {\n            throw new TypeError(\".setChoices must be called either with array of choices with a function resulting into Promise of array of choices\");\n        }\n        this.containerOuter.removeLoadingState();\n        this._store.withTxn(function () {\n            if (clearSearchFlag) {\n                _this._isSearching = false;\n            }\n            // Clear choices if needed\n            if (replaceChoices) {\n                _this.clearChoices(true, replaceItems);\n            }\n            var isDefaultValue = value === 'value';\n            var isDefaultLabel = label === 'label';\n            choicesArrayOrFetcher.forEach(function (groupOrChoice) {\n                if ('choices' in groupOrChoice) {\n                    var group = groupOrChoice;\n                    if (!isDefaultLabel) {\n                        group = __assign(__assign({}, group), { label: group[label] });\n                    }\n                    _this._addGroup(mapInputToChoice(group, true));\n                }\n                else {\n                    var choice = groupOrChoice;\n                    if (!isDefaultLabel || !isDefaultValue) {\n                        choice = __assign(__assign({}, choice), { value: choice[value], label: choice[label] });\n                    }\n                    var choiceFull = mapInputToChoice(choice, false);\n                    _this._addChoice(choiceFull);\n                    if (choiceFull.placeholder && !_this._hasNonChoicePlaceholder) {\n                        _this._placeholderValue = unwrapStringForEscaped(choiceFull.label);\n                    }\n                }\n            });\n            _this.unhighlightAll();\n        });\n        // @todo integrate with Store\n        this._searcher.reset();\n        return this;\n    };\n    Choices.prototype.refresh = function (withEvents, selectFirstOption, deselectAll) {\n        var _this = this;\n        if (withEvents === void 0) { withEvents = false; }\n        if (selectFirstOption === void 0) { selectFirstOption = false; }\n        if (deselectAll === void 0) { deselectAll = false; }\n        if (!this._isSelectElement) {\n            if (!this.config.silent) {\n                console.warn('refresh method can only be used on choices backed by a <select> element');\n            }\n            return this;\n        }\n        this._store.withTxn(function () {\n            var choicesFromOptions = _this.passedElement.optionsAsChoices();\n            // Build the list of items which require preserving\n            var existingItems = {};\n            if (!deselectAll) {\n                _this._store.items.forEach(function (choice) {\n                    if (choice.id && choice.active && choice.selected) {\n                        existingItems[choice.value] = true;\n                    }\n                });\n            }\n            _this.clearStore(false);\n            var updateChoice = function (choice) {\n                if (deselectAll) {\n                    _this._store.dispatch(removeItem$1(choice));\n                }\n                else if (existingItems[choice.value]) {\n                    choice.selected = true;\n                }\n            };\n            choicesFromOptions.forEach(function (groupOrChoice) {\n                if ('choices' in groupOrChoice) {\n                    groupOrChoice.choices.forEach(updateChoice);\n                    return;\n                }\n                updateChoice(groupOrChoice);\n            });\n            /* @todo only generate add events for the added options instead of all\n            if (withEvents) {\n              items.forEach((choice) => {\n                if (existingItems[choice.value]) {\n                  this.passedElement.triggerEvent(\n                    EventType.removeItem,\n                    this._getChoiceForEvent(choice),\n                  );\n                }\n              });\n            }\n            */\n            // load new choices & items\n            _this._addPredefinedChoices(choicesFromOptions, selectFirstOption, withEvents);\n            // re-do search if required\n            if (_this._isSearching) {\n                _this._searchChoices(_this.input.value);\n            }\n        });\n        return this;\n    };\n    Choices.prototype.removeChoice = function (value) {\n        var choice = this._store.choices.find(function (c) { return c.value === value; });\n        if (!choice) {\n            return this;\n        }\n        this._clearNotice();\n        this._store.dispatch(removeChoice(choice));\n        // @todo integrate with Store\n        this._searcher.reset();\n        if (choice.selected) {\n            this.passedElement.triggerEvent(EventType.removeItem, getChoiceForOutput(choice));\n        }\n        return this;\n    };\n    Choices.prototype.clearChoices = function (clearOptions, clearItems) {\n        var _this = this;\n        if (clearOptions === void 0) { clearOptions = true; }\n        if (clearItems === void 0) { clearItems = false; }\n        if (clearOptions) {\n            if (clearItems) {\n                this.passedElement.element.replaceChildren('');\n            }\n            else {\n                this.passedElement.element.querySelectorAll(':not([selected])').forEach(function (el) {\n                    el.remove();\n                });\n            }\n        }\n        this.itemList.element.replaceChildren('');\n        this.choiceList.element.replaceChildren('');\n        this._clearNotice();\n        this._store.withTxn(function () {\n            var items = clearItems ? [] : _this._store.items;\n            _this._store.reset();\n            items.forEach(function (item) {\n                _this._store.dispatch(addChoice(item));\n                _this._store.dispatch(addItem(item));\n            });\n        });\n        // @todo integrate with Store\n        this._searcher.reset();\n        return this;\n    };\n    Choices.prototype.clearStore = function (clearOptions) {\n        if (clearOptions === void 0) { clearOptions = true; }\n        this.clearChoices(clearOptions, true);\n        this._stopSearch();\n        this._lastAddedChoiceId = 0;\n        this._lastAddedGroupId = 0;\n        return this;\n    };\n    Choices.prototype.clearInput = function () {\n        var shouldSetInputWidth = !this._isSelectOneElement;\n        this.input.clear(shouldSetInputWidth);\n        this._stopSearch();\n        return this;\n    };\n    Choices.prototype._validateConfig = function () {\n        var config = this.config;\n        var invalidConfigOptions = diff(config, DEFAULT_CONFIG);\n        if (invalidConfigOptions.length) {\n            console.warn('Unknown config option(s) passed', invalidConfigOptions.join(', '));\n        }\n        if (config.allowHTML && config.allowHtmlUserInput) {\n            if (config.addItems) {\n                console.warn('Warning: allowHTML/allowHtmlUserInput/addItems all being true is strongly not recommended and may lead to XSS attacks');\n            }\n            if (config.addChoices) {\n                console.warn('Warning: allowHTML/allowHtmlUserInput/addChoices all being true is strongly not recommended and may lead to XSS attacks');\n            }\n        }\n    };\n    Choices.prototype._render = function (changes) {\n        if (changes === void 0) { changes = { choices: true, groups: true, items: true }; }\n        if (this._store.inTxn()) {\n            return;\n        }\n        if (this._isSelectElement) {\n            if (changes.choices || changes.groups) {\n                this._renderChoices();\n            }\n        }\n        if (changes.items) {\n            this._renderItems();\n        }\n    };\n    Choices.prototype._renderChoices = function () {\n        var _this = this;\n        if (!this._canAddItems()) {\n            return; // block rendering choices if the input limit is reached.\n        }\n        var _a = this, config = _a.config, isSearching = _a._isSearching;\n        var _b = this._store, activeGroups = _b.activeGroups, activeChoices = _b.activeChoices;\n        var renderLimit = isSearching ? config.searchResultLimit : config.renderChoiceLimit;\n        if (this._isSelectElement) {\n            var backingOptions = activeChoices.filter(function (choice) { return !choice.element; });\n            if (backingOptions.length) {\n                this.passedElement.addOptions(backingOptions);\n            }\n        }\n        var fragment = document.createDocumentFragment();\n        var renderableChoices = function (choices) {\n            return choices.filter(function (choice) {\n                return !choice.placeholder &&\n                    (isSearching\n                        ? (config.searchRenderSelectedChoices || !choice.selected) && !!choice.rank\n                        : config.renderSelectedChoices || !choice.selected);\n            });\n        };\n        var showLabel = config.appendGroupInSearch && isSearching;\n        var selectableChoices = false;\n        var highlightedEl = null;\n        var renderChoices = function (choices, withinGroup) {\n            if (isSearching) {\n                // sortByRank is used to ensure stable sorting, as scores are non-unique\n                // this additionally ensures fuseOptions.sortFn is not ignored\n                choices.sort(sortByRank);\n            }\n            else if (config.shouldSort) {\n                choices.sort(config.sorter);\n            }\n            var choiceLimit = choices.length;\n            choiceLimit = !withinGroup && renderLimit > 0 && choiceLimit > renderLimit ? renderLimit : choiceLimit;\n            choiceLimit--;\n            choices.every(function (choice, index) {\n                // choiceEl being empty signals the contents has probably significantly changed\n                var dropdownItem = choice.choiceEl ||\n                    _this._templates.choice(config, choice, config.itemSelectText, showLabel && choice.group ? choice.group.label : undefined);\n                choice.choiceEl = dropdownItem;\n                fragment.appendChild(dropdownItem);\n                if (isSearching || !choice.selected) {\n                    selectableChoices = true;\n                }\n                else if (!highlightedEl) {\n                    highlightedEl = dropdownItem;\n                }\n                return index < choiceLimit;\n            });\n        };\n        if (activeChoices.length) {\n            if (config.resetScrollPosition) {\n                requestAnimationFrame(function () { return _this.choiceList.scrollToTop(); });\n            }\n            if (!this._hasNonChoicePlaceholder && !isSearching && this._isSelectOneElement) {\n                // If we have a placeholder choice along with groups\n                renderChoices(activeChoices.filter(function (choice) { return choice.placeholder && !choice.group; }), false);\n            }\n            // If we have grouped options\n            if (activeGroups.length && !isSearching) {\n                if (config.shouldSort) {\n                    activeGroups.sort(config.sorter);\n                }\n                // render Choices without group first, regardless of sort, otherwise they won't be distinguishable\n                // from the last group\n                renderChoices(activeChoices.filter(function (choice) { return !choice.placeholder && !choice.group; }), false);\n                activeGroups.forEach(function (group) {\n                    var groupChoices = renderableChoices(group.choices);\n                    if (groupChoices.length) {\n                        if (group.label) {\n                            var dropdownGroup = group.groupEl || _this._templates.choiceGroup(_this.config, group);\n                            group.groupEl = dropdownGroup;\n                            dropdownGroup.remove();\n                            fragment.appendChild(dropdownGroup);\n                        }\n                        renderChoices(groupChoices, true);\n                    }\n                });\n            }\n            else {\n                renderChoices(renderableChoices(activeChoices), false);\n            }\n        }\n        if (!selectableChoices && (isSearching || !fragment.children.length || !config.renderSelectedChoices)) {\n            if (!this._notice) {\n                this._notice = {\n                    text: resolveStringFunction(isSearching ? config.noResultsText : config.noChoicesText),\n                    type: isSearching ? NoticeTypes.noResults : NoticeTypes.noChoices,\n                };\n            }\n            fragment.replaceChildren('');\n        }\n        this._renderNotice(fragment);\n        this.choiceList.element.replaceChildren(fragment);\n        this._highlightChoice(highlightedEl);\n    };\n    Choices.prototype._renderItems = function () {\n        var _this = this;\n        var items = this._store.items || [];\n        var itemList = this.itemList.element;\n        var config = this.config;\n        var fragment = document.createDocumentFragment();\n        var itemFromList = function (item) {\n            return itemList.querySelector(\"[data-item][data-id=\\\"\".concat(item.id, \"\\\"]\"));\n        };\n        var addItemToFragment = function (item) {\n            var el = item.itemEl;\n            if (el && el.parentElement) {\n                return;\n            }\n            el = itemFromList(item) || _this._templates.item(config, item, config.removeItemButton);\n            item.itemEl = el;\n            fragment.appendChild(el);\n        };\n        // new items\n        items.forEach(addItemToFragment);\n        var addedItems = !!fragment.childNodes.length;\n        if (this._isSelectOneElement) {\n            var existingItems = itemList.children.length;\n            if (addedItems || existingItems > 1) {\n                var placeholder = itemList.querySelector(getClassNamesSelector(config.classNames.placeholder));\n                if (placeholder) {\n                    placeholder.remove();\n                }\n            }\n            else if (!addedItems && !existingItems && this._placeholderValue) {\n                addedItems = true;\n                addItemToFragment(mapInputToChoice({\n                    selected: true,\n                    value: '',\n                    label: this._placeholderValue,\n                    placeholder: true,\n                }, false));\n            }\n        }\n        if (addedItems) {\n            itemList.append(fragment);\n            if (config.shouldSortItems && !this._isSelectOneElement) {\n                items.sort(config.sorter);\n                // push sorting into the DOM\n                items.forEach(function (item) {\n                    var el = itemFromList(item);\n                    if (el) {\n                        el.remove();\n                        fragment.append(el);\n                    }\n                });\n                itemList.append(fragment);\n            }\n        }\n        if (this._isTextElement) {\n            // Update the value of the hidden input\n            this.passedElement.value = items.map(function (_a) {\n                var value = _a.value;\n                return value;\n            }).join(config.delimiter);\n        }\n    };\n    Choices.prototype._displayNotice = function (text, type, openDropdown) {\n        if (openDropdown === void 0) { openDropdown = true; }\n        var oldNotice = this._notice;\n        if (oldNotice &&\n            ((oldNotice.type === type && oldNotice.text === text) ||\n                (oldNotice.type === NoticeTypes.addChoice &&\n                    (type === NoticeTypes.noResults || type === NoticeTypes.noChoices)))) {\n            if (openDropdown) {\n                this.showDropdown(true);\n            }\n            return;\n        }\n        this._clearNotice();\n        this._notice = text\n            ? {\n                text: text,\n                type: type,\n            }\n            : undefined;\n        this._renderNotice();\n        if (openDropdown && text) {\n            this.showDropdown(true);\n        }\n    };\n    Choices.prototype._clearNotice = function () {\n        if (!this._notice) {\n            return;\n        }\n        var noticeElement = this.choiceList.element.querySelector(getClassNamesSelector(this.config.classNames.notice));\n        if (noticeElement) {\n            noticeElement.remove();\n        }\n        this._notice = undefined;\n    };\n    Choices.prototype._renderNotice = function (fragment) {\n        var noticeConf = this._notice;\n        if (noticeConf) {\n            var notice = this._templates.notice(this.config, noticeConf.text, noticeConf.type);\n            if (fragment) {\n                fragment.append(notice);\n            }\n            else {\n                this.choiceList.prepend(notice);\n            }\n        }\n    };\n    /**\n     * @deprecated Use utils.getChoiceForOutput\n     */\n    // eslint-disable-next-line class-methods-use-this\n    Choices.prototype._getChoiceForOutput = function (choice, keyCode) {\n        return getChoiceForOutput(choice, keyCode);\n    };\n    Choices.prototype._triggerChange = function (value) {\n        if (value === undefined || value === null) {\n            return;\n        }\n        this.passedElement.triggerEvent(EventType.change, {\n            value: value,\n        });\n    };\n    Choices.prototype._handleButtonAction = function (element) {\n        var _this = this;\n        var items = this._store.items;\n        if (!items.length || !this.config.removeItems || !this.config.removeItemButton) {\n            return;\n        }\n        var id = element && parseDataSetId(element.closest('[data-id]'));\n        var itemToRemove = id && items.find(function (item) { return item.id === id; });\n        if (!itemToRemove) {\n            return;\n        }\n        this._store.withTxn(function () {\n            // Remove item associated with button\n            _this._removeItem(itemToRemove);\n            _this._triggerChange(itemToRemove.value);\n            if (_this._isSelectOneElement && !_this._hasNonChoicePlaceholder) {\n                var placeholderChoice = (_this.config.shouldSort ? _this._store.choices.reverse() : _this._store.choices).find(function (choice) { return choice.placeholder; });\n                if (placeholderChoice) {\n                    _this._addItem(placeholderChoice);\n                    _this.unhighlightAll();\n                    if (placeholderChoice.value) {\n                        _this._triggerChange(placeholderChoice.value);\n                    }\n                }\n            }\n        });\n    };\n    Choices.prototype._handleItemAction = function (element, hasShiftKey) {\n        var _this = this;\n        if (hasShiftKey === void 0) { hasShiftKey = false; }\n        var items = this._store.items;\n        if (!items.length || !this.config.removeItems || this._isSelectOneElement) {\n            return;\n        }\n        var id = parseDataSetId(element);\n        if (!id) {\n            return;\n        }\n        // We only want to select one item with a click\n        // so we deselect any items that aren't the target\n        // unless shift is being pressed\n        items.forEach(function (item) {\n            if (item.id === id && !item.highlighted) {\n                _this.highlightItem(item);\n            }\n            else if (!hasShiftKey && item.highlighted) {\n                _this.unhighlightItem(item);\n            }\n        });\n        // Focus input as without focus, a user cannot do anything with a\n        // highlighted item\n        this.input.focus();\n    };\n    Choices.prototype._handleChoiceAction = function (element) {\n        var _this = this;\n        // If we are clicking on an option\n        var id = parseDataSetId(element);\n        var choice = id && this._store.getChoiceById(id);\n        if (!choice || choice.disabled) {\n            return false;\n        }\n        var hasActiveDropdown = this.dropdown.isActive;\n        if (!choice.selected) {\n            if (!this._canAddItems()) {\n                return true; // causes _onEnterKey to early out\n            }\n            this._store.withTxn(function () {\n                _this._addItem(choice, true, true);\n                _this.clearInput();\n                _this.unhighlightAll();\n            });\n            this._triggerChange(choice.value);\n        }\n        // We want to close the dropdown if we are dealing with a single select box\n        if (hasActiveDropdown && this.config.closeDropdownOnSelect) {\n            this.hideDropdown(true);\n            this.containerOuter.element.focus();\n        }\n        return true;\n    };\n    Choices.prototype._handleBackspace = function (items) {\n        var config = this.config;\n        if (!config.removeItems || !items.length) {\n            return;\n        }\n        var lastItem = items[items.length - 1];\n        var hasHighlightedItems = items.some(function (item) { return item.highlighted; });\n        // If editing the last item is allowed and there are not other selected items,\n        // we can edit the item value. Otherwise if we can remove items, remove all selected items\n        if (config.editItems && !hasHighlightedItems && lastItem) {\n            this.input.value = lastItem.value;\n            this.input.setWidth();\n            this._removeItem(lastItem);\n            this._triggerChange(lastItem.value);\n        }\n        else {\n            if (!hasHighlightedItems) {\n                // Highlight last item if none already highlighted\n                this.highlightItem(lastItem, false);\n            }\n            this.removeHighlightedItems(true);\n        }\n    };\n    Choices.prototype._loadChoices = function () {\n        var _a;\n        var _this = this;\n        var config = this.config;\n        if (this._isTextElement) {\n            // Assign preset items from passed object first\n            this._presetChoices = config.items.map(function (e) { return mapInputToChoice(e, false); });\n            // Add any values passed from attribute\n            if (this.passedElement.value) {\n                var elementItems = this.passedElement.value\n                    .split(config.delimiter)\n                    .map(function (e) { return mapInputToChoice(e, false, _this.config.allowHtmlUserInput); });\n                this._presetChoices = this._presetChoices.concat(elementItems);\n            }\n            this._presetChoices.forEach(function (choice) {\n                choice.selected = true;\n            });\n        }\n        else if (this._isSelectElement) {\n            // Assign preset choices from passed object\n            this._presetChoices = config.choices.map(function (e) { return mapInputToChoice(e, true); });\n            // Create array of choices from option elements\n            var choicesFromOptions = this.passedElement.optionsAsChoices();\n            if (choicesFromOptions) {\n                (_a = this._presetChoices).push.apply(_a, choicesFromOptions);\n            }\n        }\n    };\n    Choices.prototype._handleLoadingState = function (setLoading) {\n        if (setLoading === void 0) { setLoading = true; }\n        var el = this.itemList.element;\n        if (setLoading) {\n            this.disable();\n            this.containerOuter.addLoadingState();\n            if (this._isSelectOneElement) {\n                el.replaceChildren(this._templates.placeholder(this.config, this.config.loadingText));\n            }\n            else {\n                this.input.placeholder = this.config.loadingText;\n            }\n        }\n        else {\n            this.enable();\n            this.containerOuter.removeLoadingState();\n            if (this._isSelectOneElement) {\n                el.replaceChildren('');\n                this._render();\n            }\n            else {\n                this.input.placeholder = this._placeholderValue || '';\n            }\n        }\n    };\n    Choices.prototype._handleSearch = function (value) {\n        if (!this.input.isFocussed) {\n            return;\n        }\n        // Check that we have a value to search and the input was an alphanumeric character\n        if (value !== null && typeof value !== 'undefined' && value.length >= this.config.searchFloor) {\n            var resultCount = this.config.searchChoices ? this._searchChoices(value) : 0;\n            if (resultCount !== null) {\n                // Trigger search event\n                this.passedElement.triggerEvent(EventType.search, {\n                    value: value,\n                    resultCount: resultCount,\n                });\n            }\n        }\n        else if (this._store.choices.some(function (option) { return !option.active; })) {\n            this._stopSearch();\n        }\n    };\n    Choices.prototype._canAddItems = function () {\n        var config = this.config;\n        var maxItemCount = config.maxItemCount, maxItemText = config.maxItemText;\n        if (!config.singleModeForMultiSelect && maxItemCount > 0 && maxItemCount <= this._store.items.length) {\n            this.choiceList.element.replaceChildren('');\n            this._notice = undefined;\n            this._displayNotice(typeof maxItemText === 'function' ? maxItemText(maxItemCount) : maxItemText, NoticeTypes.addChoice);\n            return false;\n        }\n        if (this._notice && this._notice.type === NoticeTypes.addChoice) {\n            this._clearNotice();\n        }\n        return true;\n    };\n    Choices.prototype._canCreateItem = function (value) {\n        var config = this.config;\n        var canAddItem = true;\n        var notice = '';\n        if (canAddItem && typeof config.addItemFilter === 'function' && !config.addItemFilter(value)) {\n            canAddItem = false;\n            notice = resolveNoticeFunction(config.customAddItemText, value, undefined);\n        }\n        if (canAddItem) {\n            var foundChoice = this._store.choices.find(function (choice) { return config.valueComparer(choice.value, value); });\n            if (foundChoice) {\n                if (this._isSelectElement) {\n                    // for exact matches, do not prompt to add it as a custom choice\n                    this._displayNotice('', NoticeTypes.addChoice);\n                    return false;\n                }\n                if (!config.duplicateItemsAllowed) {\n                    canAddItem = false;\n                    notice = resolveNoticeFunction(config.uniqueItemText, value, undefined);\n                }\n            }\n        }\n        if (canAddItem) {\n            notice = resolveNoticeFunction(config.addItemText, value, undefined);\n        }\n        if (notice) {\n            this._displayNotice(notice, NoticeTypes.addChoice);\n        }\n        return canAddItem;\n    };\n    Choices.prototype._searchChoices = function (value) {\n        var newValue = value.trim().replace(/\\s{2,}/, ' ');\n        // signal input didn't change search\n        if (!newValue.length || newValue === this._currentValue) {\n            return null;\n        }\n        var searcher = this._searcher;\n        if (searcher.isEmptyIndex()) {\n            searcher.index(this._store.searchableChoices);\n        }\n        // If new value matches the desired length and is not the same as the current value with a space\n        var results = searcher.search(newValue);\n        this._currentValue = newValue;\n        this._highlightPosition = 0;\n        this._isSearching = true;\n        var notice = this._notice;\n        var noticeType = notice && notice.type;\n        if (noticeType !== NoticeTypes.addChoice) {\n            if (!results.length) {\n                this._displayNotice(resolveStringFunction(this.config.noResultsText), NoticeTypes.noResults);\n            }\n            else {\n                this._clearNotice();\n            }\n        }\n        this._store.dispatch(filterChoices(results));\n        return results.length;\n    };\n    Choices.prototype._stopSearch = function () {\n        if (this._isSearching) {\n            this._currentValue = '';\n            this._isSearching = false;\n            this._clearNotice();\n            this._store.dispatch(activateChoices(true));\n            this.passedElement.triggerEvent(EventType.search, {\n                value: '',\n                resultCount: 0,\n            });\n        }\n    };\n    Choices.prototype._addEventListeners = function () {\n        var documentElement = this._docRoot;\n        var outerElement = this.containerOuter.element;\n        var inputElement = this.input.element;\n        var passedElement = this.passedElement.element;\n        // capture events - can cancel event processing or propagation\n        documentElement.addEventListener('touchend', this._onTouchEnd, true);\n        outerElement.addEventListener('keydown', this._onKeyDown, true);\n        outerElement.addEventListener('mousedown', this._onMouseDown, true);\n        // passive events - doesn't call `preventDefault` or `stopPropagation`\n        documentElement.addEventListener('click', this._onClick, { passive: true });\n        documentElement.addEventListener('touchmove', this._onTouchMove, {\n            passive: true,\n        });\n        this.dropdown.element.addEventListener('mouseover', this._onMouseOver, {\n            passive: true,\n        });\n        if (this._isSelectOneElement) {\n            outerElement.addEventListener('focus', this._onFocus, {\n                passive: true,\n            });\n            outerElement.addEventListener('blur', this._onBlur, {\n                passive: true,\n            });\n        }\n        inputElement.addEventListener('keyup', this._onKeyUp, {\n            passive: true,\n        });\n        inputElement.addEventListener('input', this._onInput, {\n            passive: true,\n        });\n        inputElement.addEventListener('focus', this._onFocus, {\n            passive: true,\n        });\n        inputElement.addEventListener('blur', this._onBlur, {\n            passive: true,\n        });\n        if (inputElement.form) {\n            inputElement.form.addEventListener('reset', this._onFormReset, {\n                passive: true,\n            });\n        }\n        if (passedElement.hasAttribute('required')) {\n            passedElement.addEventListener('change', this._onChange, {\n                passive: true,\n            });\n            passedElement.addEventListener('invalid', this._onInvalid, {\n                passive: true,\n            });\n        }\n        this.input.addEventListeners();\n    };\n    Choices.prototype._removeEventListeners = function () {\n        var documentElement = this._docRoot;\n        var outerElement = this.containerOuter.element;\n        var inputElement = this.input.element;\n        var passedElement = this.passedElement.element;\n        documentElement.removeEventListener('touchend', this._onTouchEnd, true);\n        outerElement.removeEventListener('keydown', this._onKeyDown, true);\n        outerElement.removeEventListener('mousedown', this._onMouseDown, true);\n        documentElement.removeEventListener('click', this._onClick);\n        documentElement.removeEventListener('touchmove', this._onTouchMove);\n        this.dropdown.element.removeEventListener('mouseover', this._onMouseOver);\n        if (this._isSelectOneElement) {\n            outerElement.removeEventListener('focus', this._onFocus);\n            outerElement.removeEventListener('blur', this._onBlur);\n        }\n        inputElement.removeEventListener('keyup', this._onKeyUp);\n        inputElement.removeEventListener('input', this._onInput);\n        inputElement.removeEventListener('focus', this._onFocus);\n        inputElement.removeEventListener('blur', this._onBlur);\n        if (inputElement.form) {\n            inputElement.form.removeEventListener('reset', this._onFormReset);\n        }\n        if (passedElement.hasAttribute('required')) {\n            passedElement.removeEventListener('change', this._onChange);\n            passedElement.removeEventListener('invalid', this._onInvalid);\n        }\n        this.input.removeEventListeners();\n    };\n    Choices.prototype._onKeyDown = function (event) {\n        var keyCode = event.keyCode;\n        var hasActiveDropdown = this.dropdown.isActive;\n        /*\n        See:\n        https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key\n        https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values\n        https://en.wikipedia.org/wiki/UTF-16#Code_points_from_U+010000_to_U+10FFFF - UTF-16 surrogate pairs\n        https://stackoverflow.com/a/70866532 - \"Unidentified\" for mobile\n        http://www.unicode.org/versions/Unicode5.2.0/ch16.pdf#G19635 - U+FFFF is reserved (Section 16.7)\n    \n        Logic: when a key event is sent, `event.key` represents its printable value _or_ one\n        of a large list of special values indicating meta keys/functionality. In addition,\n        key events for compose functionality contain a value of `Dead` when mid-composition.\n    \n        I can't quite verify it, but non-English IMEs may also be able to generate key codes\n        for code points in the surrogate-pair range, which could potentially be seen as having\n        key.length > 1. Since `Fn` is one of the special keys, we can't distinguish by that\n        alone.\n    \n        Here, key.length === 1 means we know for sure the input was printable and not a special\n        `key` value. When the length is greater than 1, it could be either a printable surrogate\n        pair or a special `key` value. We can tell the difference by checking if the _character\n        code_ value (not code point!) is in the \"surrogate pair\" range or not.\n    \n        We don't use .codePointAt because an invalid code point would return 65535, which wouldn't\n        pass the >= 0x10000 check we would otherwise use.\n    \n        > ...The Unicode Standard sets aside 66 noncharacter code points. The last two code points\n        > of each plane are noncharacters: U+FFFE and U+FFFF on the BMP...\n        */\n        var wasPrintableChar = event.key.length === 1 ||\n            (event.key.length === 2 && event.key.charCodeAt(0) >= 0xd800) ||\n            event.key === 'Unidentified';\n        /*\n          We do not show the dropdown if focusing out with esc or navigating through input fields.\n          An activated search can still be opened with any other key.\n         */\n        if (!this._isTextElement &&\n            !hasActiveDropdown &&\n            keyCode !== KeyCodeMap.ESC_KEY &&\n            keyCode !== KeyCodeMap.TAB_KEY &&\n            keyCode !== KeyCodeMap.SHIFT_KEY) {\n            this.showDropdown();\n            if (!this.input.isFocussed && wasPrintableChar) {\n                /*\n                  We update the input value with the pressed key as\n                  the input was not focussed at the time of key press\n                  therefore does not have the value of the key.\n                */\n                this.input.value += event.key;\n                // browsers interpret a space as pagedown\n                if (event.key === ' ') {\n                    event.preventDefault();\n                }\n            }\n        }\n        switch (keyCode) {\n            case KeyCodeMap.A_KEY:\n                return this._onSelectKey(event, this.itemList.element.hasChildNodes());\n            case KeyCodeMap.ENTER_KEY:\n                return this._onEnterKey(event, hasActiveDropdown);\n            case KeyCodeMap.ESC_KEY:\n                return this._onEscapeKey(event, hasActiveDropdown);\n            case KeyCodeMap.UP_KEY:\n            case KeyCodeMap.PAGE_UP_KEY:\n            case KeyCodeMap.DOWN_KEY:\n            case KeyCodeMap.PAGE_DOWN_KEY:\n                return this._onDirectionKey(event, hasActiveDropdown);\n            case KeyCodeMap.DELETE_KEY:\n            case KeyCodeMap.BACK_KEY:\n                return this._onDeleteKey(event, this._store.items, this.input.isFocussed);\n        }\n    };\n    Choices.prototype._onKeyUp = function ( /* event: KeyboardEvent */) {\n        this._canSearch = this.config.searchEnabled;\n    };\n    Choices.prototype._onInput = function ( /* event: InputEvent */) {\n        var value = this.input.value;\n        if (!value) {\n            if (this._isTextElement) {\n                this.hideDropdown(true);\n            }\n            else {\n                this._stopSearch();\n            }\n            return;\n        }\n        if (!this._canAddItems()) {\n            return;\n        }\n        if (this._canSearch) {\n            // do the search even if the entered text can not be added\n            this._handleSearch(value);\n        }\n        if (!this._canAddUserChoices) {\n            return;\n        }\n        // determine if a notice needs to be displayed for why a search result can't be added\n        this._canCreateItem(value);\n        if (this._isSelectElement) {\n            this._highlightPosition = 0; // reset to select the notice and/or exact match\n            this._highlightChoice();\n        }\n    };\n    Choices.prototype._onSelectKey = function (event, hasItems) {\n        // If CTRL + A or CMD + A have been pressed and there are items to select\n        if ((event.ctrlKey || event.metaKey) && hasItems) {\n            this._canSearch = false;\n            var shouldHightlightAll = this.config.removeItems && !this.input.value && this.input.element === document.activeElement;\n            if (shouldHightlightAll) {\n                this.highlightAll();\n            }\n        }\n    };\n    Choices.prototype._onEnterKey = function (event, hasActiveDropdown) {\n        var _this = this;\n        var value = this.input.value;\n        var target = event.target;\n        event.preventDefault();\n        if (target && target.hasAttribute('data-button')) {\n            this._handleButtonAction(target);\n            return;\n        }\n        if (!hasActiveDropdown) {\n            if (this._isSelectElement || this._notice) {\n                this.showDropdown();\n            }\n            return;\n        }\n        var highlightedChoice = this.dropdown.element.querySelector(getClassNamesSelector(this.config.classNames.highlightedState));\n        if (highlightedChoice && this._handleChoiceAction(highlightedChoice)) {\n            return;\n        }\n        if (!target || !value) {\n            this.hideDropdown(true);\n            return;\n        }\n        if (!this._canAddItems()) {\n            return;\n        }\n        var addedItem = false;\n        this._store.withTxn(function () {\n            addedItem = _this._findAndSelectChoiceByValue(value, true);\n            if (!addedItem) {\n                if (!_this._canAddUserChoices) {\n                    return;\n                }\n                if (!_this._canCreateItem(value)) {\n                    return;\n                }\n                _this._addChoice(mapInputToChoice(value, false, _this.config.allowHtmlUserInput), true, true);\n                addedItem = true;\n            }\n            _this.clearInput();\n            _this.unhighlightAll();\n        });\n        if (!addedItem) {\n            return;\n        }\n        this._triggerChange(value);\n        if (this.config.closeDropdownOnSelect) {\n            this.hideDropdown(true);\n        }\n    };\n    Choices.prototype._onEscapeKey = function (event, hasActiveDropdown) {\n        if (hasActiveDropdown) {\n            event.stopPropagation();\n            this.hideDropdown(true);\n            this._stopSearch();\n            this.containerOuter.element.focus();\n        }\n    };\n    Choices.prototype._onDirectionKey = function (event, hasActiveDropdown) {\n        var keyCode = event.keyCode;\n        // If up or down key is pressed, traverse through options\n        if (hasActiveDropdown || this._isSelectOneElement) {\n            this.showDropdown();\n            this._canSearch = false;\n            var directionInt = keyCode === KeyCodeMap.DOWN_KEY || keyCode === KeyCodeMap.PAGE_DOWN_KEY ? 1 : -1;\n            var skipKey = event.metaKey || keyCode === KeyCodeMap.PAGE_DOWN_KEY || keyCode === KeyCodeMap.PAGE_UP_KEY;\n            var nextEl = void 0;\n            if (skipKey) {\n                if (directionInt > 0) {\n                    nextEl = this.dropdown.element.querySelector(\"\".concat(selectableChoiceIdentifier, \":last-of-type\"));\n                }\n                else {\n                    nextEl = this.dropdown.element.querySelector(selectableChoiceIdentifier);\n                }\n            }\n            else {\n                var currentEl = this.dropdown.element.querySelector(getClassNamesSelector(this.config.classNames.highlightedState));\n                if (currentEl) {\n                    nextEl = getAdjacentEl(currentEl, selectableChoiceIdentifier, directionInt);\n                }\n                else {\n                    nextEl = this.dropdown.element.querySelector(selectableChoiceIdentifier);\n                }\n            }\n            if (nextEl) {\n                // We prevent default to stop the cursor moving\n                // when pressing the arrow\n                if (!isScrolledIntoView(nextEl, this.choiceList.element, directionInt)) {\n                    this.choiceList.scrollToChildElement(nextEl, directionInt);\n                }\n                this._highlightChoice(nextEl);\n            }\n            // Prevent default to maintain cursor position whilst\n            // traversing dropdown options\n            event.preventDefault();\n        }\n    };\n    Choices.prototype._onDeleteKey = function (event, items, hasFocusedInput) {\n        // If backspace or delete key is pressed and the input has no value\n        if (!this._isSelectOneElement && !event.target.value && hasFocusedInput) {\n            this._handleBackspace(items);\n            event.preventDefault();\n        }\n    };\n    Choices.prototype._onTouchMove = function () {\n        if (this._wasTap) {\n            this._wasTap = false;\n        }\n    };\n    Choices.prototype._onTouchEnd = function (event) {\n        var target = (event || event.touches[0]).target;\n        var touchWasWithinContainer = this._wasTap && this.containerOuter.element.contains(target);\n        if (touchWasWithinContainer) {\n            var containerWasExactTarget = target === this.containerOuter.element || target === this.containerInner.element;\n            if (containerWasExactTarget) {\n                if (this._isTextElement) {\n                    this.input.focus();\n                }\n                else if (this._isSelectMultipleElement) {\n                    this.showDropdown();\n                }\n            }\n            // Prevents focus event firing\n            event.stopPropagation();\n        }\n        this._wasTap = true;\n    };\n    /**\n     * Handles mousedown event in capture mode for containetOuter.element\n     */\n    Choices.prototype._onMouseDown = function (event) {\n        var target = event.target;\n        if (!(target instanceof Element)) {\n            return;\n        }\n        // If we have our mouse down on the scrollbar and are on IE11...\n        if (IS_IE11 && this.choiceList.element.contains(target)) {\n            // check if click was on a scrollbar area\n            var firstChoice = this.choiceList.element.firstElementChild;\n            this._isScrollingOnIe =\n                this._direction === 'ltr' ? event.offsetX >= firstChoice.offsetWidth : event.offsetX < firstChoice.offsetLeft;\n        }\n        if (target === this.input.element) {\n            return;\n        }\n        var item = target.closest('[data-button],[data-item],[data-choice]');\n        if (item instanceof HTMLElement) {\n            if ('button' in item.dataset) {\n                this._handleButtonAction(item);\n            }\n            else if ('item' in item.dataset) {\n                this._handleItemAction(item, event.shiftKey);\n            }\n            else if ('choice' in item.dataset) {\n                this._handleChoiceAction(item);\n            }\n        }\n        event.preventDefault();\n    };\n    /**\n     * Handles mouseover event over this.dropdown\n     * @param {MouseEvent} event\n     */\n    Choices.prototype._onMouseOver = function (_a) {\n        var target = _a.target;\n        if (target instanceof HTMLElement && 'choice' in target.dataset) {\n            this._highlightChoice(target);\n        }\n    };\n    Choices.prototype._onClick = function (_a) {\n        var target = _a.target;\n        var containerOuter = this.containerOuter;\n        var clickWasWithinContainer = containerOuter.element.contains(target);\n        if (clickWasWithinContainer) {\n            if (!this.dropdown.isActive && !containerOuter.isDisabled) {\n                if (this._isTextElement) {\n                    if (document.activeElement !== this.input.element) {\n                        this.input.focus();\n                    }\n                }\n                else {\n                    this.showDropdown();\n                    containerOuter.element.focus();\n                }\n            }\n            else if (this._isSelectOneElement &&\n                target !== this.input.element &&\n                !this.dropdown.element.contains(target)) {\n                this.hideDropdown();\n            }\n        }\n        else {\n            containerOuter.removeFocusState();\n            this.hideDropdown(true);\n            this.unhighlightAll();\n        }\n    };\n    Choices.prototype._onFocus = function (_a) {\n        var target = _a.target;\n        var containerOuter = this.containerOuter;\n        var focusWasWithinContainer = target && containerOuter.element.contains(target);\n        if (!focusWasWithinContainer) {\n            return;\n        }\n        var targetIsInput = target === this.input.element;\n        if (this._isTextElement) {\n            if (targetIsInput) {\n                containerOuter.addFocusState();\n            }\n        }\n        else if (this._isSelectMultipleElement) {\n            if (targetIsInput) {\n                this.showDropdown(true);\n                // If element is a select box, the focused element is the container and the dropdown\n                // isn't already open, focus and show dropdown\n                containerOuter.addFocusState();\n            }\n        }\n        else {\n            containerOuter.addFocusState();\n            if (targetIsInput) {\n                this.showDropdown(true);\n            }\n        }\n    };\n    Choices.prototype._onBlur = function (_a) {\n        var target = _a.target;\n        var containerOuter = this.containerOuter;\n        var blurWasWithinContainer = target && containerOuter.element.contains(target);\n        if (blurWasWithinContainer && !this._isScrollingOnIe) {\n            if (target === this.input.element) {\n                containerOuter.removeFocusState();\n                this.hideDropdown(true);\n                if (this._isTextElement || this._isSelectMultipleElement) {\n                    this.unhighlightAll();\n                }\n            }\n            else if (target === this.containerOuter.element) {\n                // Remove the focus state when the past outerContainer was the target\n                containerOuter.removeFocusState();\n                // Also close the dropdown if search is disabled\n                if (!this.config.searchEnabled) {\n                    this.hideDropdown(true);\n                }\n            }\n        }\n        else {\n            // On IE11, clicking the scollbar blurs our input and thus\n            // closes the dropdown. To stop this, we refocus our input\n            // if we know we are on IE *and* are scrolling.\n            this._isScrollingOnIe = false;\n            this.input.element.focus();\n        }\n    };\n    Choices.prototype._onFormReset = function () {\n        var _this = this;\n        this._store.withTxn(function () {\n            _this.clearInput();\n            _this.hideDropdown();\n            _this.refresh(false, false, true);\n            if (_this._initialItems.length) {\n                _this.setChoiceByValue(_this._initialItems);\n            }\n        });\n    };\n    Choices.prototype._onChange = function (event) {\n        if (!event.target.checkValidity()) {\n            return;\n        }\n        this.containerOuter.removeInvalidState();\n    };\n    Choices.prototype._onInvalid = function () {\n        this.containerOuter.addInvalidState();\n    };\n    /**\n     * Removes any highlighted choice options\n     */\n    Choices.prototype._removeHighlightedChoices = function () {\n        var highlightedState = this.config.classNames.highlightedState;\n        var highlightedChoices = Array.from(this.dropdown.element.querySelectorAll(getClassNamesSelector(highlightedState)));\n        // Remove any highlighted choices\n        highlightedChoices.forEach(function (choice) {\n            removeClassesFromElement(choice, highlightedState);\n            choice.setAttribute('aria-selected', 'false');\n        });\n    };\n    Choices.prototype._highlightChoice = function (el) {\n        if (el === void 0) { el = null; }\n        var choices = Array.from(this.dropdown.element.querySelectorAll(selectableChoiceIdentifier));\n        if (!choices.length) {\n            return;\n        }\n        var passedEl = el;\n        var highlightedState = this.config.classNames.highlightedState;\n        this._removeHighlightedChoices();\n        if (passedEl) {\n            this._highlightPosition = choices.indexOf(passedEl);\n        }\n        else {\n            // Highlight choice based on last known highlight location\n            if (choices.length > this._highlightPosition) {\n                // If we have an option to highlight\n                passedEl = choices[this._highlightPosition];\n            }\n            else {\n                // Otherwise highlight the option before\n                passedEl = choices[choices.length - 1];\n            }\n            if (!passedEl) {\n                passedEl = choices[0];\n            }\n        }\n        addClassesToElement(passedEl, highlightedState);\n        passedEl.setAttribute('aria-selected', 'true');\n        this.passedElement.triggerEvent(EventType.highlightChoice, {\n            el: passedEl,\n        });\n        if (this.dropdown.isActive) {\n            // IE11 ignores aria-label and blocks virtual keyboard\n            // if aria-activedescendant is set without a dropdown\n            this.input.setActiveDescendant(passedEl.id);\n            this.containerOuter.setActiveDescendant(passedEl.id);\n        }\n    };\n    Choices.prototype._addItem = function (item, withEvents, userTriggered) {\n        if (withEvents === void 0) { withEvents = true; }\n        if (userTriggered === void 0) { userTriggered = false; }\n        if (!item.id) {\n            throw new TypeError('item.id must be set before _addItem is called for a choice/item');\n        }\n        if (this.config.singleModeForMultiSelect || this._isSelectOneElement) {\n            this.removeActiveItems(item.id);\n        }\n        this._store.dispatch(addItem(item));\n        if (withEvents) {\n            var eventChoice = getChoiceForOutput(item);\n            this.passedElement.triggerEvent(EventType.addItem, eventChoice);\n            if (userTriggered) {\n                this.passedElement.triggerEvent(EventType.choice, eventChoice);\n            }\n        }\n    };\n    Choices.prototype._removeItem = function (item) {\n        if (!item.id) {\n            return;\n        }\n        this._store.dispatch(removeItem$1(item));\n        var notice = this._notice;\n        if (notice && notice.type === NoticeTypes.noChoices) {\n            this._clearNotice();\n        }\n        this.passedElement.triggerEvent(EventType.removeItem, getChoiceForOutput(item));\n    };\n    Choices.prototype._addChoice = function (choice, withEvents, userTriggered) {\n        if (withEvents === void 0) { withEvents = true; }\n        if (userTriggered === void 0) { userTriggered = false; }\n        if (choice.id) {\n            throw new TypeError('Can not re-add a choice which has already been added');\n        }\n        var config = this.config;\n        if (!config.duplicateItemsAllowed && this._store.choices.find(function (c) { return config.valueComparer(c.value, choice.value); })) {\n            return;\n        }\n        // Generate unique id, in-place update is required so chaining _addItem works as expected\n        this._lastAddedChoiceId++;\n        choice.id = this._lastAddedChoiceId;\n        choice.elementId = \"\".concat(this._baseId, \"-\").concat(this._idNames.itemChoice, \"-\").concat(choice.id);\n        var prependValue = config.prependValue, appendValue = config.appendValue;\n        if (prependValue) {\n            choice.value = prependValue + choice.value;\n        }\n        if (appendValue) {\n            choice.value += appendValue.toString();\n        }\n        if ((prependValue || appendValue) && choice.element) {\n            choice.element.value = choice.value;\n        }\n        this._clearNotice();\n        this._store.dispatch(addChoice(choice));\n        if (choice.selected) {\n            this._addItem(choice, withEvents, userTriggered);\n        }\n    };\n    Choices.prototype._addGroup = function (group, withEvents) {\n        var _this = this;\n        if (withEvents === void 0) { withEvents = true; }\n        if (group.id) {\n            throw new TypeError('Can not re-add a group which has already been added');\n        }\n        this._store.dispatch(addGroup(group));\n        if (!group.choices) {\n            return;\n        }\n        // add unique id for the group(s), and do not store the full list of choices in this group\n        this._lastAddedGroupId++;\n        group.id = this._lastAddedGroupId;\n        group.choices.forEach(function (item) {\n            item.group = group;\n            if (group.disabled) {\n                item.disabled = true;\n            }\n            _this._addChoice(item, withEvents);\n        });\n    };\n    Choices.prototype._createTemplates = function () {\n        var _this = this;\n        var callbackOnCreateTemplates = this.config.callbackOnCreateTemplates;\n        var userTemplates = {};\n        if (typeof callbackOnCreateTemplates === 'function') {\n            userTemplates = callbackOnCreateTemplates.call(this, strToEl, escapeForTemplate, getClassNames);\n        }\n        var templating = {};\n        Object.keys(this._templates).forEach(function (name) {\n            if (name in userTemplates) {\n                templating[name] = userTemplates[name].bind(_this);\n            }\n            else {\n                templating[name] = _this._templates[name].bind(_this);\n            }\n        });\n        this._templates = templating;\n    };\n    Choices.prototype._createElements = function () {\n        var templating = this._templates;\n        var _a = this, config = _a.config, isSelectOneElement = _a._isSelectOneElement;\n        var position = config.position, classNames = config.classNames;\n        var elementType = this._elementType;\n        this.containerOuter = new Container({\n            element: templating.containerOuter(config, this._direction, this._isSelectElement, isSelectOneElement, config.searchEnabled, elementType, config.labelId),\n            classNames: classNames,\n            type: elementType,\n            position: position,\n        });\n        this.containerInner = new Container({\n            element: templating.containerInner(config),\n            classNames: classNames,\n            type: elementType,\n            position: position,\n        });\n        this.input = new Input({\n            element: templating.input(config, this._placeholderValue),\n            classNames: classNames,\n            type: elementType,\n            preventPaste: !config.paste,\n        });\n        this.choiceList = new List({\n            element: templating.choiceList(config, isSelectOneElement),\n        });\n        this.itemList = new List({\n            element: templating.itemList(config, isSelectOneElement),\n        });\n        this.dropdown = new Dropdown({\n            element: templating.dropdown(config),\n            classNames: classNames,\n            type: elementType,\n        });\n    };\n    Choices.prototype._createStructure = function () {\n        var _a = this, containerInner = _a.containerInner, containerOuter = _a.containerOuter, passedElement = _a.passedElement;\n        var dropdownElement = this.dropdown.element;\n        // Hide original element\n        passedElement.conceal();\n        // Wrap input in container preserving DOM ordering\n        containerInner.wrap(passedElement.element);\n        // Wrapper inner container with outer container\n        containerOuter.wrap(containerInner.element);\n        containerOuter.element.appendChild(containerInner.element);\n        containerOuter.element.appendChild(dropdownElement);\n        containerInner.element.appendChild(this.itemList.element);\n        dropdownElement.appendChild(this.choiceList.element);\n        if (this._isSelectOneElement) {\n            this.input.placeholder = this.config.searchPlaceholderValue || '';\n            if (this.config.searchEnabled) {\n                dropdownElement.insertBefore(this.input.element, dropdownElement.firstChild);\n            }\n        }\n        else {\n            if (!this._isSelectMultipleElement || this.config.searchEnabled) {\n                containerInner.element.appendChild(this.input.element);\n            }\n            if (this._placeholderValue) {\n                this.input.placeholder = this._placeholderValue;\n            }\n            this.input.setWidth();\n        }\n        this._highlightPosition = 0;\n        this._isSearching = false;\n    };\n    Choices.prototype._initStore = function () {\n        var _this = this;\n        this._store.subscribe(this._render).withTxn(function () {\n            _this._addPredefinedChoices(_this._presetChoices, _this._isSelectOneElement && !_this._hasNonChoicePlaceholder, false);\n        });\n        if (!this._store.choices.length || (this._isSelectOneElement && this._hasNonChoicePlaceholder)) {\n            this._render();\n        }\n    };\n    Choices.prototype._addPredefinedChoices = function (choices, selectFirstOption, withEvents) {\n        var _this = this;\n        if (selectFirstOption === void 0) { selectFirstOption = false; }\n        if (withEvents === void 0) { withEvents = true; }\n        if (selectFirstOption) {\n            /**\n             * If there is a selected choice already or the choice is not the first in\n             * the array, add each choice normally.\n             *\n             * Otherwise we pre-select the first enabled choice in the array (\"select-one\" only)\n             */\n            var noSelectedChoices = choices.findIndex(function (choice) { return choice.selected; }) === -1;\n            if (noSelectedChoices) {\n                choices.some(function (choice) {\n                    if (choice.disabled || 'choices' in choice) {\n                        return false;\n                    }\n                    choice.selected = true;\n                    return true;\n                });\n            }\n        }\n        choices.forEach(function (item) {\n            if ('choices' in item) {\n                if (_this._isSelectElement) {\n                    _this._addGroup(item, withEvents);\n                }\n            }\n            else {\n                _this._addChoice(item, withEvents);\n            }\n        });\n    };\n    Choices.prototype._findAndSelectChoiceByValue = function (value, userTriggered) {\n        var _this = this;\n        if (userTriggered === void 0) { userTriggered = false; }\n        // Check 'value' property exists and the choice isn't already selected\n        var foundChoice = this._store.choices.find(function (choice) { return _this.config.valueComparer(choice.value, value); });\n        if (foundChoice && !foundChoice.disabled && !foundChoice.selected) {\n            this._addItem(foundChoice, true, userTriggered);\n            return true;\n        }\n        return false;\n    };\n    Choices.prototype._generatePlaceholderValue = function () {\n        var config = this.config;\n        if (!config.placeholder) {\n            return null;\n        }\n        if (this._hasNonChoicePlaceholder) {\n            return config.placeholderValue;\n        }\n        if (this._isSelectElement) {\n            var placeholderOption = this.passedElement.placeholderOption;\n            return placeholderOption ? placeholderOption.text : null;\n        }\n        return null;\n    };\n    Choices.prototype._warnChoicesInitFailed = function (caller) {\n        if (this.config.silent) {\n            return;\n        }\n        if (!this.initialised) {\n            throw new TypeError(\"\".concat(caller, \" called on a non-initialised instance of Choices\"));\n        }\n        else if (!this.initialisedOK) {\n            throw new TypeError(\"\".concat(caller, \" called for an element which has multiple instances of Choices initialised on it\"));\n        }\n    };\n    Choices.version = '11.2.1';\n    return Choices;\n}());\n\nexport { Choices as default };\n"
  },
  {
    "path": "public/assets/scripts/choices.search-basic.js",
    "content": "/*! choices.js v11.2.1 | © 2026 Josh Johnson | https://github.com/Choices-js/Choices#readme */\n\n(function (global, factory) {\n    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :\n    typeof define === 'function' && define.amd ? define(factory) :\n    (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Choices = factory());\n})(this, (function () { 'use strict';\n\n    /******************************************************************************\n    Copyright (c) Microsoft Corporation.\n\n    Permission to use, copy, modify, and/or distribute this software for any\n    purpose with or without fee is hereby granted.\n\n    THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\n    REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\n    AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\n    INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\n    LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\n    OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\n    PERFORMANCE OF THIS SOFTWARE.\n    ***************************************************************************** */\n    /* global Reflect, Promise, SuppressedError, Symbol */\n\n    var extendStatics = function (d, b) {\n      extendStatics = Object.setPrototypeOf || {\n        __proto__: []\n      } instanceof Array && function (d, b) {\n        d.__proto__ = b;\n      } || function (d, b) {\n        for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p];\n      };\n      return extendStatics(d, b);\n    };\n    function __extends(d, b) {\n      if (typeof b !== \"function\" && b !== null) throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\n      extendStatics(d, b);\n      function __() {\n        this.constructor = d;\n      }\n      d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\n    }\n    var __assign = function () {\n      __assign = Object.assign || function __assign(t) {\n        for (var s, i = 1, n = arguments.length; i < n; i++) {\n          s = arguments[i];\n          for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\n        }\n        return t;\n      };\n      return __assign.apply(this, arguments);\n    };\n    function __spreadArray(to, from, pack) {\n      if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\n        if (ar || !(i in from)) {\n          if (!ar) ar = Array.prototype.slice.call(from, 0, i);\n          ar[i] = from[i];\n        }\n      }\n      return to.concat(ar || Array.prototype.slice.call(from));\n    }\n    typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\n      var e = new Error(message);\n      return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\n    };\n\n    var ActionType = {\n        ADD_CHOICE: 'ADD_CHOICE',\n        REMOVE_CHOICE: 'REMOVE_CHOICE',\n        FILTER_CHOICES: 'FILTER_CHOICES',\n        ACTIVATE_CHOICES: 'ACTIVATE_CHOICES',\n        CLEAR_CHOICES: 'CLEAR_CHOICES',\n        ADD_GROUP: 'ADD_GROUP',\n        ADD_ITEM: 'ADD_ITEM',\n        REMOVE_ITEM: 'REMOVE_ITEM',\n        HIGHLIGHT_ITEM: 'HIGHLIGHT_ITEM',\n    };\n\n    var EventType = {\n        showDropdown: 'showDropdown',\n        hideDropdown: 'hideDropdown',\n        change: 'change',\n        choice: 'choice',\n        search: 'search',\n        addItem: 'addItem',\n        removeItem: 'removeItem',\n        highlightItem: 'highlightItem',\n        highlightChoice: 'highlightChoice',\n        unhighlightItem: 'unhighlightItem',\n    };\n\n    var KeyCodeMap = {\n        TAB_KEY: 9,\n        SHIFT_KEY: 16,\n        BACK_KEY: 46,\n        DELETE_KEY: 8,\n        ENTER_KEY: 13,\n        A_KEY: 65,\n        ESC_KEY: 27,\n        UP_KEY: 38,\n        DOWN_KEY: 40,\n        PAGE_UP_KEY: 33,\n        PAGE_DOWN_KEY: 34,\n    };\n\n    var ObjectsInConfig = ['fuseOptions', 'classNames'];\n\n    var PassedElementTypes = {\n        Text: 'text',\n        SelectOne: 'select-one',\n        SelectMultiple: 'select-multiple',\n    };\n\n    var addChoice = function (choice) { return ({\n        type: ActionType.ADD_CHOICE,\n        choice: choice,\n    }); };\n    var removeChoice = function (choice) { return ({\n        type: ActionType.REMOVE_CHOICE,\n        choice: choice,\n    }); };\n    var filterChoices = function (results) { return ({\n        type: ActionType.FILTER_CHOICES,\n        results: results,\n    }); };\n    var activateChoices = function (active) {\n        return ({\n            type: ActionType.ACTIVATE_CHOICES,\n            active: active,\n        });\n    };\n\n    var addGroup = function (group) { return ({\n        type: ActionType.ADD_GROUP,\n        group: group,\n    }); };\n\n    var addItem = function (item) { return ({\n        type: ActionType.ADD_ITEM,\n        item: item,\n    }); };\n    var removeItem$1 = function (item) { return ({\n        type: ActionType.REMOVE_ITEM,\n        item: item,\n    }); };\n    var highlightItem = function (item, highlighted) { return ({\n        type: ActionType.HIGHLIGHT_ITEM,\n        item: item,\n        highlighted: highlighted,\n    }); };\n\n    var getRandomNumber = function (min, max) { return Math.floor(Math.random() * (max - min) + min); };\n    var generateChars = function (length) {\n        return Array.from({ length: length }, function () { return getRandomNumber(0, 36).toString(36); }).join('');\n    };\n    var generateId = function (element, prefix) {\n        var id = element.id || (element.name && \"\".concat(element.name, \"-\").concat(generateChars(2))) || generateChars(4);\n        id = id.replace(/(:|\\.|\\[|\\]|,)/g, '');\n        id = \"\".concat(prefix, \"-\").concat(id);\n        return id;\n    };\n    var getAdjacentEl = function (startEl, selector, direction) {\n        if (direction === void 0) { direction = 1; }\n        var prop = \"\".concat(direction > 0 ? 'next' : 'previous', \"ElementSibling\");\n        var sibling = startEl[prop];\n        while (sibling) {\n            if (sibling.matches(selector)) {\n                return sibling;\n            }\n            sibling = sibling[prop];\n        }\n        return null;\n    };\n    var isScrolledIntoView = function (element, parent, direction) {\n        if (direction === void 0) { direction = 1; }\n        var isVisible;\n        if (direction > 0) {\n            // In view from bottom\n            isVisible = parent.scrollTop + parent.offsetHeight >= element.offsetTop + element.offsetHeight;\n        }\n        else {\n            // In view from top\n            isVisible = element.offsetTop >= parent.scrollTop;\n        }\n        return isVisible;\n    };\n    var sanitise = function (value) {\n        if (typeof value !== 'string') {\n            if (value === null || value === undefined) {\n                return '';\n            }\n            if (typeof value === 'object') {\n                if ('raw' in value) {\n                    return sanitise(value.raw);\n                }\n                if ('trusted' in value) {\n                    return value.trusted;\n                }\n            }\n            return value;\n        }\n        return value\n            .replace(/&/g, '&amp;')\n            .replace(/>/g, '&gt;')\n            .replace(/</g, '&lt;')\n            .replace(/'/g, '&#039;')\n            .replace(/\"/g, '&quot;');\n    };\n    var strToEl = (function () {\n        var tmpEl = document.createElement('div');\n        return function (str) {\n            tmpEl.innerHTML = str.trim();\n            var firstChild = tmpEl.children[0];\n            while (tmpEl.firstChild) {\n                tmpEl.removeChild(tmpEl.firstChild);\n            }\n            return firstChild;\n        };\n    })();\n    var resolveStringFunction = function (fn) {\n        return typeof fn === 'function' ? fn() : fn;\n    };\n    var unwrapStringForRaw = function (s) {\n        if (typeof s === 'string') {\n            return s;\n        }\n        if (typeof s === 'object') {\n            if ('trusted' in s) {\n                return s.trusted;\n            }\n            if ('raw' in s) {\n                return s.raw;\n            }\n        }\n        return '';\n    };\n    var unwrapStringForEscaped = function (s) {\n        if (typeof s === 'string') {\n            return s;\n        }\n        if (typeof s === 'object') {\n            if ('escaped' in s) {\n                return s.escaped;\n            }\n            if ('trusted' in s) {\n                return s.trusted;\n            }\n        }\n        return '';\n    };\n    var getChoiceForOutput = function (choice, keyCode) {\n        return {\n            id: choice.id,\n            highlighted: choice.highlighted,\n            labelClass: choice.labelClass,\n            labelDescription: unwrapStringForRaw(choice.labelDescription),\n            customProperties: choice.customProperties,\n            disabled: choice.disabled,\n            active: choice.active,\n            label: choice.label,\n            placeholder: choice.placeholder,\n            value: choice.value,\n            groupValue: choice.group ? choice.group.label : undefined,\n            element: choice.element,\n            keyCode: keyCode,\n        };\n    };\n    var resolveNoticeFunction = function (fn, value, item) {\n        return typeof fn === 'function' ? fn(sanitise(value), unwrapStringForRaw(value), item) : fn;\n    };\n    var escapeForTemplate = function (allowHTML, s) {\n        return allowHTML ? unwrapStringForEscaped(s) : sanitise(s);\n    };\n    var setElementHtml = function (el, allowHtml, html) {\n        el.innerHTML = escapeForTemplate(allowHtml, html);\n    };\n    var sortByAlpha = function (_a, _b) {\n        var value = _a.value, _c = _a.label, label = _c === void 0 ? value : _c;\n        var value2 = _b.value, _d = _b.label, label2 = _d === void 0 ? value2 : _d;\n        return unwrapStringForRaw(label).localeCompare(unwrapStringForRaw(label2), [], {\n            sensitivity: 'base',\n            ignorePunctuation: true,\n            numeric: true,\n        });\n    };\n    var sortByRank = function (a, b) {\n        return a.rank - b.rank;\n    };\n    var dispatchEvent = function (element, type, customArgs) {\n        if (customArgs === void 0) { customArgs = null; }\n        var event = new CustomEvent(type, {\n            detail: customArgs,\n            bubbles: true,\n            cancelable: true,\n        });\n        return element.dispatchEvent(event);\n    };\n    /**\n     * Returns an array of keys present on the first but missing on the second object\n     */\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    var diff = function (a, b) {\n        var aKeys = Object.keys(a).sort();\n        var bKeys = Object.keys(b).sort();\n        return aKeys.filter(function (i) { return bKeys.indexOf(i) < 0; });\n    };\n    var getClassNames = function (ClassNames) {\n        return Array.isArray(ClassNames) ? ClassNames : [ClassNames];\n    };\n    var getClassNamesSelector = function (option) {\n        if (option && Array.isArray(option)) {\n            return option\n                .map(function (item) {\n                return \".\".concat(item);\n            })\n                .join('');\n        }\n        return \".\".concat(option);\n    };\n    var addClassesToElement = function (element, className) {\n        var _a;\n        (_a = element.classList).add.apply(_a, getClassNames(className));\n    };\n    var removeClassesFromElement = function (element, className) {\n        var _a;\n        (_a = element.classList).remove.apply(_a, getClassNames(className));\n    };\n    var parseCustomProperties = function (customProperties) {\n        if (typeof customProperties !== 'undefined') {\n            try {\n                return JSON.parse(customProperties);\n            }\n            catch (e) {\n                return customProperties;\n            }\n        }\n        return {};\n    };\n    var updateClassList = function (item, add, remove) {\n        var itemEl = item.itemEl;\n        if (itemEl) {\n            removeClassesFromElement(itemEl, remove);\n            addClassesToElement(itemEl, add);\n        }\n    };\n\n    var Dropdown = /** @class */ (function () {\n        function Dropdown(_a) {\n            var element = _a.element, type = _a.type, classNames = _a.classNames;\n            this.element = element;\n            this.classNames = classNames;\n            this.type = type;\n            this.isActive = false;\n        }\n        /**\n         * Show dropdown to user by adding active state class\n         */\n        Dropdown.prototype.show = function () {\n            addClassesToElement(this.element, this.classNames.activeState);\n            this.element.setAttribute('aria-expanded', 'true');\n            this.isActive = true;\n            return this;\n        };\n        /**\n         * Hide dropdown from user\n         */\n        Dropdown.prototype.hide = function () {\n            removeClassesFromElement(this.element, this.classNames.activeState);\n            this.element.setAttribute('aria-expanded', 'false');\n            this.isActive = false;\n            return this;\n        };\n        return Dropdown;\n    }());\n\n    var Container = /** @class */ (function () {\n        function Container(_a) {\n            var element = _a.element, type = _a.type, classNames = _a.classNames, position = _a.position;\n            this.element = element;\n            this.classNames = classNames;\n            this.type = type;\n            this.position = position;\n            this.isOpen = false;\n            this.isFlipped = false;\n            this.isDisabled = false;\n            this.isLoading = false;\n        }\n        /**\n         * Determine whether container should be flipped based on passed\n         * dropdown position\n         */\n        Container.prototype.shouldFlip = function (dropdownPos, dropdownHeight) {\n            // If flip is enabled and the dropdown bottom position is\n            // greater than the window height flip the dropdown.\n            var shouldFlip = false;\n            if (this.position === 'auto') {\n                shouldFlip =\n                    this.element.getBoundingClientRect().top - dropdownHeight >= 0 &&\n                        !window.matchMedia(\"(min-height: \".concat(dropdownPos + 1, \"px)\")).matches;\n            }\n            else if (this.position === 'top') {\n                shouldFlip = true;\n            }\n            return shouldFlip;\n        };\n        Container.prototype.setActiveDescendant = function (activeDescendantID) {\n            this.element.setAttribute('aria-activedescendant', activeDescendantID);\n        };\n        Container.prototype.removeActiveDescendant = function () {\n            this.element.removeAttribute('aria-activedescendant');\n        };\n        Container.prototype.open = function (dropdownPos, dropdownHeight) {\n            addClassesToElement(this.element, this.classNames.openState);\n            this.element.setAttribute('aria-expanded', 'true');\n            this.isOpen = true;\n            if (this.shouldFlip(dropdownPos, dropdownHeight)) {\n                addClassesToElement(this.element, this.classNames.flippedState);\n                this.isFlipped = true;\n            }\n        };\n        Container.prototype.close = function () {\n            removeClassesFromElement(this.element, this.classNames.openState);\n            this.element.setAttribute('aria-expanded', 'false');\n            this.removeActiveDescendant();\n            this.isOpen = false;\n            // A dropdown flips if it does not have space within the page\n            if (this.isFlipped) {\n                removeClassesFromElement(this.element, this.classNames.flippedState);\n                this.isFlipped = false;\n            }\n        };\n        Container.prototype.addFocusState = function () {\n            addClassesToElement(this.element, this.classNames.focusState);\n        };\n        Container.prototype.removeFocusState = function () {\n            removeClassesFromElement(this.element, this.classNames.focusState);\n        };\n        Container.prototype.addInvalidState = function () {\n            addClassesToElement(this.element, this.classNames.invalidState);\n        };\n        Container.prototype.removeInvalidState = function () {\n            removeClassesFromElement(this.element, this.classNames.invalidState);\n        };\n        Container.prototype.enable = function () {\n            removeClassesFromElement(this.element, this.classNames.disabledState);\n            this.element.removeAttribute('aria-disabled');\n            if (this.type === PassedElementTypes.SelectOne) {\n                this.element.setAttribute('tabindex', '0');\n            }\n            this.isDisabled = false;\n        };\n        Container.prototype.disable = function () {\n            addClassesToElement(this.element, this.classNames.disabledState);\n            this.element.setAttribute('aria-disabled', 'true');\n            if (this.type === PassedElementTypes.SelectOne) {\n                this.element.setAttribute('tabindex', '-1');\n            }\n            this.isDisabled = true;\n        };\n        Container.prototype.wrap = function (element) {\n            var el = this.element;\n            var parentNode = element.parentNode;\n            if (parentNode) {\n                if (element.nextSibling) {\n                    parentNode.insertBefore(el, element.nextSibling);\n                }\n                else {\n                    parentNode.appendChild(el);\n                }\n            }\n            el.appendChild(element);\n        };\n        Container.prototype.unwrap = function (element) {\n            var el = this.element;\n            var parentNode = el.parentNode;\n            if (parentNode) {\n                // Move passed element outside this element\n                parentNode.insertBefore(element, el);\n                // Remove this element\n                parentNode.removeChild(el);\n            }\n        };\n        Container.prototype.addLoadingState = function () {\n            addClassesToElement(this.element, this.classNames.loadingState);\n            this.element.setAttribute('aria-busy', 'true');\n            this.isLoading = true;\n        };\n        Container.prototype.removeLoadingState = function () {\n            removeClassesFromElement(this.element, this.classNames.loadingState);\n            this.element.removeAttribute('aria-busy');\n            this.isLoading = false;\n        };\n        return Container;\n    }());\n\n    var Input = /** @class */ (function () {\n        function Input(_a) {\n            var element = _a.element, type = _a.type, classNames = _a.classNames, preventPaste = _a.preventPaste;\n            this.element = element;\n            this.type = type;\n            this.classNames = classNames;\n            this.preventPaste = preventPaste;\n            this.isFocussed = this.element.isEqualNode(document.activeElement);\n            this.isDisabled = element.disabled;\n            this._onPaste = this._onPaste.bind(this);\n            this._onInput = this._onInput.bind(this);\n            this._onFocus = this._onFocus.bind(this);\n            this._onBlur = this._onBlur.bind(this);\n        }\n        Object.defineProperty(Input.prototype, \"placeholder\", {\n            set: function (placeholder) {\n                this.element.placeholder = placeholder;\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(Input.prototype, \"value\", {\n            get: function () {\n                return this.element.value;\n            },\n            set: function (value) {\n                this.element.value = value;\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Input.prototype.addEventListeners = function () {\n            var el = this.element;\n            el.addEventListener('paste', this._onPaste);\n            el.addEventListener('input', this._onInput, {\n                passive: true,\n            });\n            el.addEventListener('focus', this._onFocus, {\n                passive: true,\n            });\n            el.addEventListener('blur', this._onBlur, {\n                passive: true,\n            });\n        };\n        Input.prototype.removeEventListeners = function () {\n            var el = this.element;\n            el.removeEventListener('input', this._onInput);\n            el.removeEventListener('paste', this._onPaste);\n            el.removeEventListener('focus', this._onFocus);\n            el.removeEventListener('blur', this._onBlur);\n        };\n        Input.prototype.enable = function () {\n            var el = this.element;\n            el.removeAttribute('disabled');\n            this.isDisabled = false;\n        };\n        Input.prototype.disable = function () {\n            var el = this.element;\n            el.setAttribute('disabled', '');\n            this.isDisabled = true;\n        };\n        Input.prototype.focus = function () {\n            if (!this.isFocussed) {\n                this.element.focus();\n            }\n        };\n        Input.prototype.blur = function () {\n            if (this.isFocussed) {\n                this.element.blur();\n            }\n        };\n        Input.prototype.clear = function (setWidth) {\n            if (setWidth === void 0) { setWidth = true; }\n            this.element.value = '';\n            if (setWidth) {\n                this.setWidth();\n            }\n            return this;\n        };\n        /**\n         * Set the correct input width based on placeholder\n         * value or input value\n         */\n        Input.prototype.setWidth = function () {\n            // Resize input to contents or placeholder\n            var element = this.element;\n            element.style.minWidth = \"\".concat(element.placeholder.length + 1, \"ch\");\n            element.style.width = \"\".concat(element.value.length + 1, \"ch\");\n        };\n        Input.prototype.setActiveDescendant = function (activeDescendantID) {\n            this.element.setAttribute('aria-activedescendant', activeDescendantID);\n        };\n        Input.prototype.removeActiveDescendant = function () {\n            this.element.removeAttribute('aria-activedescendant');\n        };\n        Input.prototype._onInput = function () {\n            if (this.type !== PassedElementTypes.SelectOne) {\n                this.setWidth();\n            }\n        };\n        Input.prototype._onPaste = function (event) {\n            if (this.preventPaste) {\n                event.preventDefault();\n            }\n        };\n        Input.prototype._onFocus = function () {\n            this.isFocussed = true;\n        };\n        Input.prototype._onBlur = function () {\n            this.isFocussed = false;\n        };\n        return Input;\n    }());\n\n    var SCROLLING_SPEED = 4;\n\n    var List = /** @class */ (function () {\n        function List(_a) {\n            var element = _a.element;\n            this.element = element;\n            this.scrollPos = this.element.scrollTop;\n            this.height = this.element.offsetHeight;\n        }\n        List.prototype.prepend = function (node) {\n            var child = this.element.firstElementChild;\n            if (child) {\n                this.element.insertBefore(node, child);\n            }\n            else {\n                this.element.append(node);\n            }\n        };\n        List.prototype.scrollToTop = function () {\n            this.element.scrollTop = 0;\n        };\n        List.prototype.scrollToChildElement = function (element, direction) {\n            var _this = this;\n            if (!element) {\n                return;\n            }\n            var listHeight = this.element.offsetHeight;\n            // Scroll position of dropdown\n            var listScrollPosition = this.element.scrollTop + listHeight;\n            var elementHeight = element.offsetHeight;\n            // Distance from bottom of element to top of parent\n            var elementPos = element.offsetTop + elementHeight;\n            // Difference between the element and scroll position\n            var destination = direction > 0 ? this.element.scrollTop + elementPos - listScrollPosition : element.offsetTop;\n            requestAnimationFrame(function () {\n                _this._animateScroll(destination, direction);\n            });\n        };\n        List.prototype._scrollDown = function (scrollPos, strength, destination) {\n            var easing = (destination - scrollPos) / strength;\n            var distance = easing > 1 ? easing : 1;\n            this.element.scrollTop = scrollPos + distance;\n        };\n        List.prototype._scrollUp = function (scrollPos, strength, destination) {\n            var easing = (scrollPos - destination) / strength;\n            var distance = easing > 1 ? easing : 1;\n            this.element.scrollTop = scrollPos - distance;\n        };\n        List.prototype._animateScroll = function (destination, direction) {\n            var _this = this;\n            var strength = SCROLLING_SPEED;\n            var choiceListScrollTop = this.element.scrollTop;\n            var continueAnimation = false;\n            if (direction > 0) {\n                this._scrollDown(choiceListScrollTop, strength, destination);\n                if (choiceListScrollTop < destination) {\n                    continueAnimation = true;\n                }\n            }\n            else {\n                this._scrollUp(choiceListScrollTop, strength, destination);\n                if (choiceListScrollTop > destination) {\n                    continueAnimation = true;\n                }\n            }\n            if (continueAnimation) {\n                requestAnimationFrame(function () {\n                    _this._animateScroll(destination, direction);\n                });\n            }\n        };\n        return List;\n    }());\n\n    var WrappedElement = /** @class */ (function () {\n        function WrappedElement(_a) {\n            var element = _a.element, classNames = _a.classNames;\n            this.element = element;\n            this.classNames = classNames;\n            this.isDisabled = false;\n        }\n        Object.defineProperty(WrappedElement.prototype, \"isActive\", {\n            get: function () {\n                return this.element.dataset.choice === 'active';\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(WrappedElement.prototype, \"dir\", {\n            get: function () {\n                return this.element.dir;\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(WrappedElement.prototype, \"value\", {\n            get: function () {\n                return this.element.value;\n            },\n            set: function (value) {\n                this.element.setAttribute('value', value);\n                this.element.value = value;\n            },\n            enumerable: false,\n            configurable: true\n        });\n        WrappedElement.prototype.conceal = function () {\n            var el = this.element;\n            // Hide passed input\n            addClassesToElement(el, this.classNames.input);\n            el.hidden = true;\n            // Remove element from tab index\n            el.tabIndex = -1;\n            // Backup original styles if any\n            var origStyle = el.getAttribute('style');\n            if (origStyle) {\n                el.setAttribute('data-choice-orig-style', origStyle);\n            }\n            el.setAttribute('data-choice', 'active');\n        };\n        WrappedElement.prototype.reveal = function () {\n            var el = this.element;\n            // Reinstate passed element\n            removeClassesFromElement(el, this.classNames.input);\n            el.hidden = false;\n            el.removeAttribute('tabindex');\n            // Recover original styles if any\n            var origStyle = el.getAttribute('data-choice-orig-style');\n            if (origStyle) {\n                el.removeAttribute('data-choice-orig-style');\n                el.setAttribute('style', origStyle);\n            }\n            else {\n                el.removeAttribute('style');\n            }\n            el.removeAttribute('data-choice');\n        };\n        WrappedElement.prototype.enable = function () {\n            this.element.removeAttribute('disabled');\n            this.element.disabled = false;\n            this.isDisabled = false;\n        };\n        WrappedElement.prototype.disable = function () {\n            this.element.setAttribute('disabled', '');\n            this.element.disabled = true;\n            this.isDisabled = true;\n        };\n        WrappedElement.prototype.triggerEvent = function (eventType, data) {\n            dispatchEvent(this.element, eventType, data || {});\n        };\n        return WrappedElement;\n    }());\n\n    var WrappedInput = /** @class */ (function (_super) {\n        __extends(WrappedInput, _super);\n        function WrappedInput() {\n            return _super !== null && _super.apply(this, arguments) || this;\n        }\n        return WrappedInput;\n    }(WrappedElement));\n\n    var coerceBool = function (arg, defaultValue) {\n        if (defaultValue === void 0) { defaultValue = true; }\n        return typeof arg === 'undefined' ? defaultValue : !!arg;\n    };\n    var stringToHtmlClass = function (input) {\n        if (typeof input === 'string') {\n            // eslint-disable-next-line no-param-reassign\n            input = input.split(' ').filter(function (s) { return s.length; });\n        }\n        if (Array.isArray(input) && input.length) {\n            return input;\n        }\n        return undefined;\n    };\n    var mapInputToChoice = function (value, allowGroup, allowRawString) {\n        if (allowRawString === void 0) { allowRawString = true; }\n        if (typeof value === 'string') {\n            var sanitisedValue = sanitise(value);\n            var userValue = allowRawString || sanitisedValue === value ? value : { escaped: sanitisedValue, raw: value };\n            var result_1 = mapInputToChoice({\n                value: value,\n                label: userValue,\n                selected: true,\n            }, false);\n            return result_1;\n        }\n        var groupOrChoice = value;\n        if ('choices' in groupOrChoice) {\n            if (!allowGroup) {\n                // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/optgroup\n                throw new TypeError(\"optGroup is not allowed\");\n            }\n            var group = groupOrChoice;\n            var choices = group.choices.map(function (e) { return mapInputToChoice(e, false); });\n            var result_2 = {\n                id: 0, // actual ID will be assigned during _addGroup\n                label: unwrapStringForRaw(group.label) || group.value,\n                active: !!choices.length,\n                disabled: !!group.disabled,\n                choices: choices,\n            };\n            return result_2;\n        }\n        var choice = groupOrChoice;\n        var result = {\n            id: 0, // actual ID will be assigned during _addChoice\n            group: null, // actual group will be assigned during _addGroup but before _addChoice\n            score: 0, // used in search\n            rank: 0, // used in search, stable sort order\n            value: choice.value,\n            label: choice.label || choice.value,\n            active: coerceBool(choice.active),\n            selected: coerceBool(choice.selected, false),\n            disabled: coerceBool(choice.disabled, false),\n            placeholder: coerceBool(choice.placeholder, false),\n            highlighted: false,\n            labelClass: stringToHtmlClass(choice.labelClass),\n            labelDescription: choice.labelDescription,\n            customProperties: choice.customProperties,\n        };\n        return result;\n    };\n\n    var isHtmlInputElement = function (e) { return e.tagName === 'INPUT'; };\n    var isHtmlSelectElement = function (e) { return e.tagName === 'SELECT'; };\n    var isHtmlOption = function (e) { return e.tagName === 'OPTION'; };\n    var isHtmlOptgroup = function (e) { return e.tagName === 'OPTGROUP'; };\n\n    var WrappedSelect = /** @class */ (function (_super) {\n        __extends(WrappedSelect, _super);\n        function WrappedSelect(_a) {\n            var element = _a.element, classNames = _a.classNames, template = _a.template, extractPlaceholder = _a.extractPlaceholder;\n            var _this = _super.call(this, { element: element, classNames: classNames }) || this;\n            _this.template = template;\n            _this.extractPlaceholder = extractPlaceholder;\n            return _this;\n        }\n        Object.defineProperty(WrappedSelect.prototype, \"placeholderOption\", {\n            get: function () {\n                return (this.element.querySelector('option[value=\"\"]') ||\n                    // Backward compatibility layer for the non-standard placeholder attribute supported in older versions.\n                    this.element.querySelector('option[placeholder]'));\n            },\n            enumerable: false,\n            configurable: true\n        });\n        WrappedSelect.prototype.addOptions = function (choices) {\n            var _this = this;\n            var fragment = document.createDocumentFragment();\n            choices.forEach(function (obj) {\n                var choice = obj;\n                if (choice.element) {\n                    return;\n                }\n                var option = _this.template(choice);\n                fragment.appendChild(option);\n                choice.element = option;\n            });\n            this.element.appendChild(fragment);\n        };\n        WrappedSelect.prototype.optionsAsChoices = function () {\n            var _this = this;\n            var choices = [];\n            this.element.querySelectorAll(':scope > option, :scope > optgroup').forEach(function (e) {\n                if (isHtmlOption(e)) {\n                    choices.push(_this._optionToChoice(e));\n                }\n                else if (isHtmlOptgroup(e)) {\n                    choices.push(_this._optgroupToChoice(e));\n                }\n                // todo: hr as empty optgroup, requires displaying empty opt-groups to be useful\n            });\n            return choices;\n        };\n        // eslint-disable-next-line class-methods-use-this\n        WrappedSelect.prototype._optionToChoice = function (option) {\n            // option.value returns the label if there is no value attribute, which can break legacy placeholder attribute support\n            if (!option.hasAttribute('value') && option.hasAttribute('placeholder')) {\n                option.setAttribute('value', '');\n                option.value = '';\n            }\n            return {\n                id: 0,\n                group: null,\n                score: 0,\n                rank: 0,\n                value: option.value,\n                // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/option\n                // This attribute is text for the label indicating the meaning of the option. If the `label` attribute isn't defined, its value is that of the element text content (ie `innerText`).\n                label: option.label,\n                element: option,\n                active: true,\n                // this returns true if nothing is selected on initial load, which will break placeholder support\n                selected: this.extractPlaceholder ? option.selected : option.hasAttribute('selected'),\n                disabled: option.disabled,\n                highlighted: false,\n                placeholder: this.extractPlaceholder && (!option.value || option.hasAttribute('placeholder')),\n                labelClass: typeof option.dataset.labelClass !== 'undefined' ? stringToHtmlClass(option.dataset.labelClass) : undefined,\n                labelDescription: typeof option.dataset.labelDescription !== 'undefined'\n                    ? { trusted: option.dataset.labelDescription }\n                    : undefined,\n                customProperties: parseCustomProperties(option.dataset.customProperties),\n            };\n        };\n        WrappedSelect.prototype._optgroupToChoice = function (optgroup) {\n            var _this = this;\n            var options = optgroup.querySelectorAll('option');\n            var choices = Array.from(options).map(function (option) { return _this._optionToChoice(option); });\n            return {\n                id: 0,\n                label: optgroup.label || '',\n                element: optgroup,\n                active: !!choices.length,\n                disabled: optgroup.disabled,\n                choices: choices,\n            };\n        };\n        return WrappedSelect;\n    }(WrappedElement));\n\n    var DEFAULT_CLASSNAMES = {\n        containerOuter: ['choices'],\n        containerInner: ['choices__inner'],\n        input: ['choices__input'],\n        inputCloned: ['choices__input--cloned'],\n        list: ['choices__list'],\n        listItems: ['choices__list--multiple'],\n        listSingle: ['choices__list--single'],\n        listDropdown: ['choices__list--dropdown'],\n        item: ['choices__item'],\n        itemSelectable: ['choices__item--selectable'],\n        itemDisabled: ['choices__item--disabled'],\n        itemChoice: ['choices__item--choice'],\n        description: ['choices__description'],\n        placeholder: ['choices__placeholder'],\n        group: ['choices__group'],\n        groupHeading: ['choices__heading'],\n        button: ['choices__button'],\n        activeState: ['is-active'],\n        focusState: ['is-focused'],\n        openState: ['is-open'],\n        disabledState: ['is-disabled'],\n        highlightedState: ['is-highlighted'],\n        selectedState: ['is-selected'],\n        flippedState: ['is-flipped'],\n        loadingState: ['is-loading'],\n        invalidState: ['is-invalid'],\n        notice: ['choices__notice'],\n        addChoice: ['choices__item--selectable', 'add-choice'],\n        noResults: ['has-no-results'],\n        noChoices: ['has-no-choices'],\n    };\n    var DEFAULT_CONFIG = {\n        items: [],\n        choices: [],\n        silent: false,\n        renderChoiceLimit: -1,\n        maxItemCount: -1,\n        closeDropdownOnSelect: 'auto',\n        singleModeForMultiSelect: false,\n        addChoices: false,\n        addItems: true,\n        addItemFilter: function (value) { return !!value && value !== ''; },\n        removeItems: true,\n        removeItemButton: false,\n        removeItemButtonAlignLeft: false,\n        editItems: false,\n        allowHTML: false,\n        allowHtmlUserInput: false,\n        duplicateItemsAllowed: true,\n        delimiter: ',',\n        paste: true,\n        searchEnabled: true,\n        searchChoices: true,\n        searchDisabledChoices: false,\n        searchFloor: 1,\n        searchResultLimit: 4,\n        searchFields: ['label', 'value'],\n        position: 'auto',\n        resetScrollPosition: true,\n        shouldSort: true,\n        shouldSortItems: false,\n        sorter: sortByAlpha,\n        shadowRoot: null,\n        placeholder: true,\n        placeholderValue: null,\n        searchPlaceholderValue: null,\n        prependValue: null,\n        appendValue: null,\n        renderSelectedChoices: 'auto',\n        searchRenderSelectedChoices: true,\n        loadingText: 'Loading...',\n        noResultsText: 'No results found',\n        noChoicesText: 'No choices to choose from',\n        itemSelectText: 'Press to select',\n        uniqueItemText: 'Only unique values can be added',\n        customAddItemText: 'Only values matching specific conditions can be added',\n        addItemText: function (value) { return \"Press Enter to add <b>\\\"\".concat(value, \"\\\"</b>\"); },\n        removeItemIconText: function () { return \"Remove item\"; },\n        removeItemLabelText: function (value, _valueRaw, i) {\n            return \"Remove item: \".concat(i ? sanitise(i.label) : value);\n        },\n        maxItemText: function (maxItemCount) { return \"Only \".concat(maxItemCount, \" values can be added\"); },\n        valueComparer: function (value1, value2) { return value1 === value2; },\n        fuseOptions: {\n            includeScore: true,\n        },\n        labelId: '',\n        callbackOnInit: null,\n        callbackOnCreateTemplates: null,\n        classNames: DEFAULT_CLASSNAMES,\n        appendGroupInSearch: false,\n    };\n\n    var removeItem = function (item) {\n        var itemEl = item.itemEl;\n        if (itemEl) {\n            itemEl.remove();\n            item.itemEl = undefined;\n        }\n    };\n    function items(s, action, context) {\n        var state = s;\n        var update = true;\n        switch (action.type) {\n            case ActionType.ADD_ITEM: {\n                action.item.selected = true;\n                var el = action.item.element;\n                if (el) {\n                    el.selected = true;\n                    el.setAttribute('selected', '');\n                }\n                state.push(action.item);\n                break;\n            }\n            case ActionType.REMOVE_ITEM: {\n                action.item.selected = false;\n                var el = action.item.element;\n                if (el) {\n                    el.selected = false;\n                    el.removeAttribute('selected');\n                    // For a select-one, if all options are deselected, the first item is selected. To set a black value, select.value needs to be set\n                    var select = el.parentElement;\n                    if (select && isHtmlSelectElement(select) && select.type === PassedElementTypes.SelectOne) {\n                        select.value = '';\n                    }\n                }\n                // this is mixing concerns, but this is *so much faster*\n                removeItem(action.item);\n                state = state.filter(function (choice) { return choice.id !== action.item.id; });\n                break;\n            }\n            case ActionType.REMOVE_CHOICE: {\n                removeItem(action.choice);\n                state = state.filter(function (item) { return item.id !== action.choice.id; });\n                break;\n            }\n            case ActionType.HIGHLIGHT_ITEM: {\n                var highlighted = action.highlighted;\n                var item = state.find(function (obj) { return obj.id === action.item.id; });\n                if (item && item.highlighted !== highlighted) {\n                    item.highlighted = highlighted;\n                    if (context) {\n                        updateClassList(item, highlighted ? context.classNames.highlightedState : context.classNames.selectedState, highlighted ? context.classNames.selectedState : context.classNames.highlightedState);\n                    }\n                }\n                break;\n            }\n            default: {\n                update = false;\n                break;\n            }\n        }\n        return { state: state, update: update };\n    }\n\n    function groups(s, action) {\n        var state = s;\n        var update = true;\n        switch (action.type) {\n            case ActionType.ADD_GROUP: {\n                state.push(action.group);\n                break;\n            }\n            case ActionType.CLEAR_CHOICES: {\n                state = [];\n                break;\n            }\n            default: {\n                update = false;\n                break;\n            }\n        }\n        return { state: state, update: update };\n    }\n\n    /* eslint-disable */\n    function choices(s, action, context) {\n        var state = s;\n        var update = true;\n        switch (action.type) {\n            case ActionType.ADD_CHOICE: {\n                state.push(action.choice);\n                break;\n            }\n            case ActionType.REMOVE_CHOICE: {\n                action.choice.choiceEl = undefined;\n                if (action.choice.group) {\n                    action.choice.group.choices = action.choice.group.choices.filter(function (obj) { return obj.id !== action.choice.id; });\n                }\n                state = state.filter(function (obj) { return obj.id !== action.choice.id; });\n                break;\n            }\n            case ActionType.ADD_ITEM:\n            case ActionType.REMOVE_ITEM: {\n                action.item.choiceEl = undefined;\n                break;\n            }\n            case ActionType.FILTER_CHOICES: {\n                // avoid O(n^2) algorithm complexity when searching/filtering choices\n                var scoreLookup_1 = [];\n                action.results.forEach(function (result) {\n                    scoreLookup_1[result.item.id] = result;\n                });\n                state.forEach(function (choice) {\n                    var result = scoreLookup_1[choice.id];\n                    if (result !== undefined) {\n                        choice.score = result.score;\n                        choice.rank = result.rank;\n                        choice.active = true;\n                    }\n                    else {\n                        choice.score = 0;\n                        choice.rank = 0;\n                        choice.active = false;\n                    }\n                    if (context && context.appendGroupInSearch) {\n                        choice.choiceEl = undefined;\n                    }\n                });\n                break;\n            }\n            case ActionType.ACTIVATE_CHOICES: {\n                state.forEach(function (choice) {\n                    choice.active = action.active;\n                    if (context && context.appendGroupInSearch) {\n                        choice.choiceEl = undefined;\n                    }\n                });\n                break;\n            }\n            case ActionType.CLEAR_CHOICES: {\n                state = [];\n                break;\n            }\n            default: {\n                update = false;\n                break;\n            }\n        }\n        return { state: state, update: update };\n    }\n\n    var reducers = {\n        groups: groups,\n        items: items,\n        choices: choices,\n    };\n    var Store = /** @class */ (function () {\n        function Store(context) {\n            this._state = this.defaultState;\n            this._listeners = [];\n            this._txn = 0;\n            this._context = context;\n        }\n        Object.defineProperty(Store.prototype, \"defaultState\", {\n            // eslint-disable-next-line class-methods-use-this\n            get: function () {\n                return {\n                    groups: [],\n                    items: [],\n                    choices: [],\n                };\n            },\n            enumerable: false,\n            configurable: true\n        });\n        // eslint-disable-next-line class-methods-use-this\n        Store.prototype.changeSet = function (init) {\n            return {\n                groups: init,\n                items: init,\n                choices: init,\n            };\n        };\n        Store.prototype.reset = function () {\n            this._state = this.defaultState;\n            var changes = this.changeSet(true);\n            if (this._txn) {\n                this._changeSet = changes;\n            }\n            else {\n                this._listeners.forEach(function (l) { return l(changes); });\n            }\n        };\n        Store.prototype.subscribe = function (onChange) {\n            this._listeners.push(onChange);\n            return this;\n        };\n        Store.prototype.dispatch = function (action) {\n            var _this = this;\n            var state = this._state;\n            var hasChanges = false;\n            var changes = this._changeSet || this.changeSet(false);\n            Object.keys(reducers).forEach(function (key) {\n                var stateUpdate = reducers[key](state[key], action, _this._context);\n                if (stateUpdate.update) {\n                    hasChanges = true;\n                    changes[key] = true;\n                    state[key] = stateUpdate.state;\n                }\n            });\n            if (hasChanges) {\n                if (this._txn) {\n                    this._changeSet = changes;\n                }\n                else {\n                    this._listeners.forEach(function (l) { return l(changes); });\n                }\n            }\n        };\n        Store.prototype.withTxn = function (func) {\n            this._txn++;\n            try {\n                func();\n            }\n            finally {\n                this._txn = Math.max(0, this._txn - 1);\n                if (!this._txn) {\n                    var changeSet_1 = this._changeSet;\n                    if (changeSet_1) {\n                        this._changeSet = undefined;\n                        this._listeners.forEach(function (l) { return l(changeSet_1); });\n                    }\n                }\n            }\n        };\n        Object.defineProperty(Store.prototype, \"state\", {\n            /**\n             * Get store object\n             */\n            get: function () {\n                return this._state;\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(Store.prototype, \"items\", {\n            /**\n             * Get items from store\n             */\n            get: function () {\n                return this.state.items;\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(Store.prototype, \"highlightedActiveItems\", {\n            /**\n             * Get highlighted items from store\n             */\n            get: function () {\n                return this.items.filter(function (item) { return item.active && item.highlighted; });\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(Store.prototype, \"choices\", {\n            /**\n             * Get choices from store\n             */\n            get: function () {\n                return this.state.choices;\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(Store.prototype, \"activeChoices\", {\n            /**\n             * Get active choices from store\n             */\n            get: function () {\n                return this.choices.filter(function (choice) { return choice.active; });\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(Store.prototype, \"searchableChoices\", {\n            /**\n             * Get choices that can be searched (excluding placeholders or disabled choices)\n             */\n            get: function () {\n                var context = this._context;\n                return this.choices.filter(function (choice) { return !choice.placeholder && (context.searchDisabledChoices || !choice.disabled); });\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(Store.prototype, \"groups\", {\n            /**\n             * Get groups from store\n             */\n            get: function () {\n                return this.state.groups;\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(Store.prototype, \"activeGroups\", {\n            /**\n             * Get active groups from store\n             */\n            get: function () {\n                var _this = this;\n                return this.state.groups.filter(function (group) {\n                    var isActive = group.active && !group.disabled;\n                    var hasActiveOptions = _this.state.choices.some(function (choice) { return choice.active && !choice.disabled; });\n                    return isActive && hasActiveOptions;\n                }, []);\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Store.prototype.inTxn = function () {\n            return this._txn > 0;\n        };\n        /**\n         * Get single choice by it's ID\n         */\n        Store.prototype.getChoiceById = function (id) {\n            return this.activeChoices.find(function (choice) { return choice.id === id; });\n        };\n        /**\n         * Get group by group id\n         */\n        Store.prototype.getGroupById = function (id) {\n            return this.groups.find(function (group) { return group.id === id; });\n        };\n        return Store;\n    }());\n\n    var NoticeTypes = {\n        noChoices: 'no-choices',\n        noResults: 'no-results',\n        addChoice: 'add-choice',\n        generic: '',\n    };\n\n    function _defineProperty(e, r, t) {\n      return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {\n        value: t,\n        enumerable: true,\n        configurable: true,\n        writable: true\n      }) : e[r] = t, e;\n    }\n    function ownKeys(e, r) {\n      var t = Object.keys(e);\n      if (Object.getOwnPropertySymbols) {\n        var o = Object.getOwnPropertySymbols(e);\n        r && (o = o.filter(function (r) {\n          return Object.getOwnPropertyDescriptor(e, r).enumerable;\n        })), t.push.apply(t, o);\n      }\n      return t;\n    }\n    function _objectSpread2(e) {\n      for (var r = 1; r < arguments.length; r++) {\n        var t = null != arguments[r] ? arguments[r] : {};\n        r % 2 ? ownKeys(Object(t), true).forEach(function (r) {\n          _defineProperty(e, r, t[r]);\n        }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {\n          Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));\n        });\n      }\n      return e;\n    }\n    function _toPrimitive(t, r) {\n      if (\"object\" != typeof t || !t) return t;\n      var e = t[Symbol.toPrimitive];\n      if (void 0 !== e) {\n        var i = e.call(t, r);\n        if (\"object\" != typeof i) return i;\n        throw new TypeError(\"@@toPrimitive must return a primitive value.\");\n      }\n      return (\"string\" === r ? String : Number)(t);\n    }\n    function _toPropertyKey(t) {\n      var i = _toPrimitive(t, \"string\");\n      return \"symbol\" == typeof i ? i : i + \"\";\n    }\n\n    /**\n     * Fuse.js v7.0.0 - Lightweight fuzzy-search (http://fusejs.io)\n     *\n     * Copyright (c) 2023 Kiro Risk (http://kiro.me)\n     * All Rights Reserved. Apache Software License 2.0\n     *\n     * http://www.apache.org/licenses/LICENSE-2.0\n     */\n\n    function isArray(value) {\n      return !Array.isArray ? getTag(value) === '[object Array]' : Array.isArray(value);\n    }\n    function baseToString(value) {\n      // Exit early for strings to avoid a performance hit in some environments.\n      if (typeof value == 'string') {\n        return value;\n      }\n      let result = value + '';\n      return result == '0' && 1 / value == -Infinity ? '-0' : result;\n    }\n    function toString(value) {\n      return value == null ? '' : baseToString(value);\n    }\n    function isString(value) {\n      return typeof value === 'string';\n    }\n    function isNumber(value) {\n      return typeof value === 'number';\n    }\n\n    // Adapted from: https://github.com/lodash/lodash/blob/master/isBoolean.js\n    function isBoolean(value) {\n      return value === true || value === false || isObjectLike(value) && getTag(value) == '[object Boolean]';\n    }\n    function isObject(value) {\n      return typeof value === 'object';\n    }\n\n    // Checks if `value` is object-like.\n    function isObjectLike(value) {\n      return isObject(value) && value !== null;\n    }\n    function isDefined(value) {\n      return value !== undefined && value !== null;\n    }\n    function isBlank(value) {\n      return !value.trim().length;\n    }\n\n    // Gets the `toStringTag` of `value`.\n    // Adapted from: https://github.com/lodash/lodash/blob/master/.internal/getTag.js\n    function getTag(value) {\n      return value == null ? value === undefined ? '[object Undefined]' : '[object Null]' : Object.prototype.toString.call(value);\n    }\n    const EXTENDED_SEARCH_UNAVAILABLE = 'Extended search is not available';\n    const LOGICAL_SEARCH_UNAVAILABLE = 'Logical search is not available';\n    const INCORRECT_INDEX_TYPE = \"Incorrect 'index' type\";\n    const LOGICAL_SEARCH_INVALID_QUERY_FOR_KEY = key => `Invalid value for key ${key}`;\n    const PATTERN_LENGTH_TOO_LARGE = max => `Pattern length exceeds max of ${max}.`;\n    const MISSING_KEY_PROPERTY = name => `Missing ${name} property in key`;\n    const INVALID_KEY_WEIGHT_VALUE = key => `Property 'weight' in key '${key}' must be a positive integer`;\n    const hasOwn = Object.prototype.hasOwnProperty;\n    class KeyStore {\n      constructor(keys) {\n        this._keys = [];\n        this._keyMap = {};\n        let totalWeight = 0;\n        keys.forEach(key => {\n          let obj = createKey(key);\n          this._keys.push(obj);\n          this._keyMap[obj.id] = obj;\n          totalWeight += obj.weight;\n        });\n\n        // Normalize weights so that their sum is equal to 1\n        this._keys.forEach(key => {\n          key.weight /= totalWeight;\n        });\n      }\n      get(keyId) {\n        return this._keyMap[keyId];\n      }\n      keys() {\n        return this._keys;\n      }\n      toJSON() {\n        return JSON.stringify(this._keys);\n      }\n    }\n    function createKey(key) {\n      let path = null;\n      let id = null;\n      let src = null;\n      let weight = 1;\n      let getFn = null;\n      if (isString(key) || isArray(key)) {\n        src = key;\n        path = createKeyPath(key);\n        id = createKeyId(key);\n      } else {\n        if (!hasOwn.call(key, 'name')) {\n          throw new Error(MISSING_KEY_PROPERTY('name'));\n        }\n        const name = key.name;\n        src = name;\n        if (hasOwn.call(key, 'weight')) {\n          weight = key.weight;\n          if (weight <= 0) {\n            throw new Error(INVALID_KEY_WEIGHT_VALUE(name));\n          }\n        }\n        path = createKeyPath(name);\n        id = createKeyId(name);\n        getFn = key.getFn;\n      }\n      return {\n        path,\n        id,\n        weight,\n        src,\n        getFn\n      };\n    }\n    function createKeyPath(key) {\n      return isArray(key) ? key : key.split('.');\n    }\n    function createKeyId(key) {\n      return isArray(key) ? key.join('.') : key;\n    }\n    function get(obj, path) {\n      let list = [];\n      let arr = false;\n      const deepGet = (obj, path, index) => {\n        if (!isDefined(obj)) {\n          return;\n        }\n        if (!path[index]) {\n          // If there's no path left, we've arrived at the object we care about.\n          list.push(obj);\n        } else {\n          let key = path[index];\n          const value = obj[key];\n          if (!isDefined(value)) {\n            return;\n          }\n\n          // If we're at the last value in the path, and if it's a string/number/bool,\n          // add it to the list\n          if (index === path.length - 1 && (isString(value) || isNumber(value) || isBoolean(value))) {\n            list.push(toString(value));\n          } else if (isArray(value)) {\n            arr = true;\n            // Search each item in the array.\n            for (let i = 0, len = value.length; i < len; i += 1) {\n              deepGet(value[i], path, index + 1);\n            }\n          } else if (path.length) {\n            // An object. Recurse further.\n            deepGet(value, path, index + 1);\n          }\n        }\n      };\n\n      // Backwards compatibility (since path used to be a string)\n      deepGet(obj, isString(path) ? path.split('.') : path, 0);\n      return arr ? list : list[0];\n    }\n    const MatchOptions = {\n      // Whether the matches should be included in the result set. When `true`, each record in the result\n      // set will include the indices of the matched characters.\n      // These can consequently be used for highlighting purposes.\n      includeMatches: false,\n      // When `true`, the matching function will continue to the end of a search pattern even if\n      // a perfect match has already been located in the string.\n      findAllMatches: false,\n      // Minimum number of characters that must be matched before a result is considered a match\n      minMatchCharLength: 1\n    };\n    const BasicOptions = {\n      // When `true`, the algorithm continues searching to the end of the input even if a perfect\n      // match is found before the end of the same input.\n      isCaseSensitive: false,\n      // When true, the matching function will continue to the end of a search pattern even if\n      includeScore: false,\n      // List of properties that will be searched. This also supports nested properties.\n      keys: [],\n      // Whether to sort the result list, by score\n      shouldSort: true,\n      // Default sort function: sort by ascending score, ascending index\n      sortFn: (a, b) => a.score === b.score ? a.idx < b.idx ? -1 : 1 : a.score < b.score ? -1 : 1\n    };\n    const FuzzyOptions = {\n      // Approximately where in the text is the pattern expected to be found?\n      location: 0,\n      // At what point does the match algorithm give up. A threshold of '0.0' requires a perfect match\n      // (of both letters and location), a threshold of '1.0' would match anything.\n      threshold: 0.6,\n      // Determines how close the match must be to the fuzzy location (specified above).\n      // An exact letter match which is 'distance' characters away from the fuzzy location\n      // would score as a complete mismatch. A distance of '0' requires the match be at\n      // the exact location specified, a threshold of '1000' would require a perfect match\n      // to be within 800 characters of the fuzzy location to be found using a 0.8 threshold.\n      distance: 100\n    };\n    const AdvancedOptions = {\n      // When `true`, it enables the use of unix-like search commands\n      useExtendedSearch: false,\n      // The get function to use when fetching an object's properties.\n      // The default will search nested paths *ie foo.bar.baz*\n      getFn: get,\n      // When `true`, search will ignore `location` and `distance`, so it won't matter\n      // where in the string the pattern appears.\n      // More info: https://fusejs.io/concepts/scoring-theory.html#fuzziness-score\n      ignoreLocation: false,\n      // When `true`, the calculation for the relevance score (used for sorting) will\n      // ignore the field-length norm.\n      // More info: https://fusejs.io/concepts/scoring-theory.html#field-length-norm\n      ignoreFieldNorm: false,\n      // The weight to determine how much field length norm effects scoring.\n      fieldNormWeight: 1\n    };\n    var Config = _objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({}, BasicOptions), MatchOptions), FuzzyOptions), AdvancedOptions);\n    const SPACE = /[^ ]+/g;\n\n    // Field-length norm: the shorter the field, the higher the weight.\n    // Set to 3 decimals to reduce index size.\n    function norm(weight = 1, mantissa = 3) {\n      const cache = new Map();\n      const m = Math.pow(10, mantissa);\n      return {\n        get(value) {\n          const numTokens = value.match(SPACE).length;\n          if (cache.has(numTokens)) {\n            return cache.get(numTokens);\n          }\n\n          // Default function is 1/sqrt(x), weight makes that variable\n          const norm = 1 / Math.pow(numTokens, 0.5 * weight);\n\n          // In place of `toFixed(mantissa)`, for faster computation\n          const n = parseFloat(Math.round(norm * m) / m);\n          cache.set(numTokens, n);\n          return n;\n        },\n        clear() {\n          cache.clear();\n        }\n      };\n    }\n    class FuseIndex {\n      constructor({\n        getFn = Config.getFn,\n        fieldNormWeight = Config.fieldNormWeight\n      } = {}) {\n        this.norm = norm(fieldNormWeight, 3);\n        this.getFn = getFn;\n        this.isCreated = false;\n        this.setIndexRecords();\n      }\n      setSources(docs = []) {\n        this.docs = docs;\n      }\n      setIndexRecords(records = []) {\n        this.records = records;\n      }\n      setKeys(keys = []) {\n        this.keys = keys;\n        this._keysMap = {};\n        keys.forEach((key, idx) => {\n          this._keysMap[key.id] = idx;\n        });\n      }\n      create() {\n        if (this.isCreated || !this.docs.length) {\n          return;\n        }\n        this.isCreated = true;\n\n        // List is Array<String>\n        if (isString(this.docs[0])) {\n          this.docs.forEach((doc, docIndex) => {\n            this._addString(doc, docIndex);\n          });\n        } else {\n          // List is Array<Object>\n          this.docs.forEach((doc, docIndex) => {\n            this._addObject(doc, docIndex);\n          });\n        }\n        this.norm.clear();\n      }\n      // Adds a doc to the end of the index\n      add(doc) {\n        const idx = this.size();\n        if (isString(doc)) {\n          this._addString(doc, idx);\n        } else {\n          this._addObject(doc, idx);\n        }\n      }\n      // Removes the doc at the specified index of the index\n      removeAt(idx) {\n        this.records.splice(idx, 1);\n\n        // Change ref index of every subsquent doc\n        for (let i = idx, len = this.size(); i < len; i += 1) {\n          this.records[i].i -= 1;\n        }\n      }\n      getValueForItemAtKeyId(item, keyId) {\n        return item[this._keysMap[keyId]];\n      }\n      size() {\n        return this.records.length;\n      }\n      _addString(doc, docIndex) {\n        if (!isDefined(doc) || isBlank(doc)) {\n          return;\n        }\n        let record = {\n          v: doc,\n          i: docIndex,\n          n: this.norm.get(doc)\n        };\n        this.records.push(record);\n      }\n      _addObject(doc, docIndex) {\n        let record = {\n          i: docIndex,\n          $: {}\n        };\n\n        // Iterate over every key (i.e, path), and fetch the value at that key\n        this.keys.forEach((key, keyIndex) => {\n          let value = key.getFn ? key.getFn(doc) : this.getFn(doc, key.path);\n          if (!isDefined(value)) {\n            return;\n          }\n          if (isArray(value)) {\n            let subRecords = [];\n            const stack = [{\n              nestedArrIndex: -1,\n              value\n            }];\n            while (stack.length) {\n              const {\n                nestedArrIndex,\n                value\n              } = stack.pop();\n              if (!isDefined(value)) {\n                continue;\n              }\n              if (isString(value) && !isBlank(value)) {\n                let subRecord = {\n                  v: value,\n                  i: nestedArrIndex,\n                  n: this.norm.get(value)\n                };\n                subRecords.push(subRecord);\n              } else if (isArray(value)) {\n                value.forEach((item, k) => {\n                  stack.push({\n                    nestedArrIndex: k,\n                    value: item\n                  });\n                });\n              } else ;\n            }\n            record.$[keyIndex] = subRecords;\n          } else if (isString(value) && !isBlank(value)) {\n            let subRecord = {\n              v: value,\n              n: this.norm.get(value)\n            };\n            record.$[keyIndex] = subRecord;\n          }\n        });\n        this.records.push(record);\n      }\n      toJSON() {\n        return {\n          keys: this.keys,\n          records: this.records\n        };\n      }\n    }\n    function createIndex(keys, docs, {\n      getFn = Config.getFn,\n      fieldNormWeight = Config.fieldNormWeight\n    } = {}) {\n      const myIndex = new FuseIndex({\n        getFn,\n        fieldNormWeight\n      });\n      myIndex.setKeys(keys.map(createKey));\n      myIndex.setSources(docs);\n      myIndex.create();\n      return myIndex;\n    }\n    function parseIndex(data, {\n      getFn = Config.getFn,\n      fieldNormWeight = Config.fieldNormWeight\n    } = {}) {\n      const {\n        keys,\n        records\n      } = data;\n      const myIndex = new FuseIndex({\n        getFn,\n        fieldNormWeight\n      });\n      myIndex.setKeys(keys);\n      myIndex.setIndexRecords(records);\n      return myIndex;\n    }\n    function computeScore$1(pattern, {\n      errors = 0,\n      currentLocation = 0,\n      expectedLocation = 0,\n      distance = Config.distance,\n      ignoreLocation = Config.ignoreLocation\n    } = {}) {\n      const accuracy = errors / pattern.length;\n      if (ignoreLocation) {\n        return accuracy;\n      }\n      const proximity = Math.abs(expectedLocation - currentLocation);\n      if (!distance) {\n        // Dodge divide by zero error.\n        return proximity ? 1.0 : accuracy;\n      }\n      return accuracy + proximity / distance;\n    }\n    function convertMaskToIndices(matchmask = [], minMatchCharLength = Config.minMatchCharLength) {\n      let indices = [];\n      let start = -1;\n      let end = -1;\n      let i = 0;\n      for (let len = matchmask.length; i < len; i += 1) {\n        let match = matchmask[i];\n        if (match && start === -1) {\n          start = i;\n        } else if (!match && start !== -1) {\n          end = i - 1;\n          if (end - start + 1 >= minMatchCharLength) {\n            indices.push([start, end]);\n          }\n          start = -1;\n        }\n      }\n\n      // (i-1 - start) + 1 => i - start\n      if (matchmask[i - 1] && i - start >= minMatchCharLength) {\n        indices.push([start, i - 1]);\n      }\n      return indices;\n    }\n\n    // Machine word size\n    const MAX_BITS = 32;\n    function search(text, pattern, patternAlphabet, {\n      location = Config.location,\n      distance = Config.distance,\n      threshold = Config.threshold,\n      findAllMatches = Config.findAllMatches,\n      minMatchCharLength = Config.minMatchCharLength,\n      includeMatches = Config.includeMatches,\n      ignoreLocation = Config.ignoreLocation\n    } = {}) {\n      if (pattern.length > MAX_BITS) {\n        throw new Error(PATTERN_LENGTH_TOO_LARGE(MAX_BITS));\n      }\n      const patternLen = pattern.length;\n      // Set starting location at beginning text and initialize the alphabet.\n      const textLen = text.length;\n      // Handle the case when location > text.length\n      const expectedLocation = Math.max(0, Math.min(location, textLen));\n      // Highest score beyond which we give up.\n      let currentThreshold = threshold;\n      // Is there a nearby exact match? (speedup)\n      let bestLocation = expectedLocation;\n\n      // Performance: only computer matches when the minMatchCharLength > 1\n      // OR if `includeMatches` is true.\n      const computeMatches = minMatchCharLength > 1 || includeMatches;\n      // A mask of the matches, used for building the indices\n      const matchMask = computeMatches ? Array(textLen) : [];\n      let index;\n\n      // Get all exact matches, here for speed up\n      while ((index = text.indexOf(pattern, bestLocation)) > -1) {\n        let score = computeScore$1(pattern, {\n          currentLocation: index,\n          expectedLocation,\n          distance,\n          ignoreLocation\n        });\n        currentThreshold = Math.min(score, currentThreshold);\n        bestLocation = index + patternLen;\n        if (computeMatches) {\n          let i = 0;\n          while (i < patternLen) {\n            matchMask[index + i] = 1;\n            i += 1;\n          }\n        }\n      }\n\n      // Reset the best location\n      bestLocation = -1;\n      let lastBitArr = [];\n      let finalScore = 1;\n      let binMax = patternLen + textLen;\n      const mask = 1 << patternLen - 1;\n      for (let i = 0; i < patternLen; i += 1) {\n        // Scan for the best match; each iteration allows for one more error.\n        // Run a binary search to determine how far from the match location we can stray\n        // at this error level.\n        let binMin = 0;\n        let binMid = binMax;\n        while (binMin < binMid) {\n          const score = computeScore$1(pattern, {\n            errors: i,\n            currentLocation: expectedLocation + binMid,\n            expectedLocation,\n            distance,\n            ignoreLocation\n          });\n          if (score <= currentThreshold) {\n            binMin = binMid;\n          } else {\n            binMax = binMid;\n          }\n          binMid = Math.floor((binMax - binMin) / 2 + binMin);\n        }\n\n        // Use the result from this iteration as the maximum for the next.\n        binMax = binMid;\n        let start = Math.max(1, expectedLocation - binMid + 1);\n        let finish = findAllMatches ? textLen : Math.min(expectedLocation + binMid, textLen) + patternLen;\n\n        // Initialize the bit array\n        let bitArr = Array(finish + 2);\n        bitArr[finish + 1] = (1 << i) - 1;\n        for (let j = finish; j >= start; j -= 1) {\n          let currentLocation = j - 1;\n          let charMatch = patternAlphabet[text.charAt(currentLocation)];\n          if (computeMatches) {\n            // Speed up: quick bool to int conversion (i.e, `charMatch ? 1 : 0`)\n            matchMask[currentLocation] = +!!charMatch;\n          }\n\n          // First pass: exact match\n          bitArr[j] = (bitArr[j + 1] << 1 | 1) & charMatch;\n\n          // Subsequent passes: fuzzy match\n          if (i) {\n            bitArr[j] |= (lastBitArr[j + 1] | lastBitArr[j]) << 1 | 1 | lastBitArr[j + 1];\n          }\n          if (bitArr[j] & mask) {\n            finalScore = computeScore$1(pattern, {\n              errors: i,\n              currentLocation,\n              expectedLocation,\n              distance,\n              ignoreLocation\n            });\n\n            // This match will almost certainly be better than any existing match.\n            // But check anyway.\n            if (finalScore <= currentThreshold) {\n              // Indeed it is\n              currentThreshold = finalScore;\n              bestLocation = currentLocation;\n\n              // Already passed `loc`, downhill from here on in.\n              if (bestLocation <= expectedLocation) {\n                break;\n              }\n\n              // When passing `bestLocation`, don't exceed our current distance from `expectedLocation`.\n              start = Math.max(1, 2 * expectedLocation - bestLocation);\n            }\n          }\n        }\n\n        // No hope for a (better) match at greater error levels.\n        const score = computeScore$1(pattern, {\n          errors: i + 1,\n          currentLocation: expectedLocation,\n          expectedLocation,\n          distance,\n          ignoreLocation\n        });\n        if (score > currentThreshold) {\n          break;\n        }\n        lastBitArr = bitArr;\n      }\n      const result = {\n        isMatch: bestLocation >= 0,\n        // Count exact matches (those with a score of 0) to be \"almost\" exact\n        score: Math.max(0.001, finalScore)\n      };\n      if (computeMatches) {\n        const indices = convertMaskToIndices(matchMask, minMatchCharLength);\n        if (!indices.length) {\n          result.isMatch = false;\n        } else if (includeMatches) {\n          result.indices = indices;\n        }\n      }\n      return result;\n    }\n    function createPatternAlphabet(pattern) {\n      let mask = {};\n      for (let i = 0, len = pattern.length; i < len; i += 1) {\n        const char = pattern.charAt(i);\n        mask[char] = (mask[char] || 0) | 1 << len - i - 1;\n      }\n      return mask;\n    }\n    class BitapSearch {\n      constructor(pattern, {\n        location = Config.location,\n        threshold = Config.threshold,\n        distance = Config.distance,\n        includeMatches = Config.includeMatches,\n        findAllMatches = Config.findAllMatches,\n        minMatchCharLength = Config.minMatchCharLength,\n        isCaseSensitive = Config.isCaseSensitive,\n        ignoreLocation = Config.ignoreLocation\n      } = {}) {\n        this.options = {\n          location,\n          threshold,\n          distance,\n          includeMatches,\n          findAllMatches,\n          minMatchCharLength,\n          isCaseSensitive,\n          ignoreLocation\n        };\n        this.pattern = isCaseSensitive ? pattern : pattern.toLowerCase();\n        this.chunks = [];\n        if (!this.pattern.length) {\n          return;\n        }\n        const addChunk = (pattern, startIndex) => {\n          this.chunks.push({\n            pattern,\n            alphabet: createPatternAlphabet(pattern),\n            startIndex\n          });\n        };\n        const len = this.pattern.length;\n        if (len > MAX_BITS) {\n          let i = 0;\n          const remainder = len % MAX_BITS;\n          const end = len - remainder;\n          while (i < end) {\n            addChunk(this.pattern.substr(i, MAX_BITS), i);\n            i += MAX_BITS;\n          }\n          if (remainder) {\n            const startIndex = len - MAX_BITS;\n            addChunk(this.pattern.substr(startIndex), startIndex);\n          }\n        } else {\n          addChunk(this.pattern, 0);\n        }\n      }\n      searchIn(text) {\n        const {\n          isCaseSensitive,\n          includeMatches\n        } = this.options;\n        if (!isCaseSensitive) {\n          text = text.toLowerCase();\n        }\n\n        // Exact match\n        if (this.pattern === text) {\n          let result = {\n            isMatch: true,\n            score: 0\n          };\n          if (includeMatches) {\n            result.indices = [[0, text.length - 1]];\n          }\n          return result;\n        }\n\n        // Otherwise, use Bitap algorithm\n        const {\n          location,\n          distance,\n          threshold,\n          findAllMatches,\n          minMatchCharLength,\n          ignoreLocation\n        } = this.options;\n        let allIndices = [];\n        let totalScore = 0;\n        let hasMatches = false;\n        this.chunks.forEach(({\n          pattern,\n          alphabet,\n          startIndex\n        }) => {\n          const {\n            isMatch,\n            score,\n            indices\n          } = search(text, pattern, alphabet, {\n            location: location + startIndex,\n            distance,\n            threshold,\n            findAllMatches,\n            minMatchCharLength,\n            includeMatches,\n            ignoreLocation\n          });\n          if (isMatch) {\n            hasMatches = true;\n          }\n          totalScore += score;\n          if (isMatch && indices) {\n            allIndices = [...allIndices, ...indices];\n          }\n        });\n        let result = {\n          isMatch: hasMatches,\n          score: hasMatches ? totalScore / this.chunks.length : 1\n        };\n        if (hasMatches && includeMatches) {\n          result.indices = allIndices;\n        }\n        return result;\n      }\n    }\n    const registeredSearchers = [];\n    function createSearcher(pattern, options) {\n      for (let i = 0, len = registeredSearchers.length; i < len; i += 1) {\n        let searcherClass = registeredSearchers[i];\n        if (searcherClass.condition(pattern, options)) {\n          return new searcherClass(pattern, options);\n        }\n      }\n      return new BitapSearch(pattern, options);\n    }\n    const LogicalOperator = {\n      AND: '$and',\n      OR: '$or'\n    };\n    const KeyType = {\n      PATH: '$path',\n      PATTERN: '$val'\n    };\n    const isExpression = query => !!(query[LogicalOperator.AND] || query[LogicalOperator.OR]);\n    const isPath = query => !!query[KeyType.PATH];\n    const isLeaf = query => !isArray(query) && isObject(query) && !isExpression(query);\n    const convertToExplicit = query => ({\n      [LogicalOperator.AND]: Object.keys(query).map(key => ({\n        [key]: query[key]\n      }))\n    });\n\n    // When `auto` is `true`, the parse function will infer and initialize and add\n    // the appropriate `Searcher` instance\n    function parse(query, options, {\n      auto = true\n    } = {}) {\n      const next = query => {\n        let keys = Object.keys(query);\n        const isQueryPath = isPath(query);\n        if (!isQueryPath && keys.length > 1 && !isExpression(query)) {\n          return next(convertToExplicit(query));\n        }\n        if (isLeaf(query)) {\n          const key = isQueryPath ? query[KeyType.PATH] : keys[0];\n          const pattern = isQueryPath ? query[KeyType.PATTERN] : query[key];\n          if (!isString(pattern)) {\n            throw new Error(LOGICAL_SEARCH_INVALID_QUERY_FOR_KEY(key));\n          }\n          const obj = {\n            keyId: createKeyId(key),\n            pattern\n          };\n          if (auto) {\n            obj.searcher = createSearcher(pattern, options);\n          }\n          return obj;\n        }\n        let node = {\n          children: [],\n          operator: keys[0]\n        };\n        keys.forEach(key => {\n          const value = query[key];\n          if (isArray(value)) {\n            value.forEach(item => {\n              node.children.push(next(item));\n            });\n          }\n        });\n        return node;\n      };\n      if (!isExpression(query)) {\n        query = convertToExplicit(query);\n      }\n      return next(query);\n    }\n\n    // Practical scoring function\n    function computeScore(results, {\n      ignoreFieldNorm = Config.ignoreFieldNorm\n    }) {\n      results.forEach(result => {\n        let totalScore = 1;\n        result.matches.forEach(({\n          key,\n          norm,\n          score\n        }) => {\n          const weight = key ? key.weight : null;\n          totalScore *= Math.pow(score === 0 && weight ? Number.EPSILON : score, (weight || 1) * (ignoreFieldNorm ? 1 : norm));\n        });\n        result.score = totalScore;\n      });\n    }\n    function transformMatches(result, data) {\n      const matches = result.matches;\n      data.matches = [];\n      if (!isDefined(matches)) {\n        return;\n      }\n      matches.forEach(match => {\n        if (!isDefined(match.indices) || !match.indices.length) {\n          return;\n        }\n        const {\n          indices,\n          value\n        } = match;\n        let obj = {\n          indices,\n          value\n        };\n        if (match.key) {\n          obj.key = match.key.src;\n        }\n        if (match.idx > -1) {\n          obj.refIndex = match.idx;\n        }\n        data.matches.push(obj);\n      });\n    }\n    function transformScore(result, data) {\n      data.score = result.score;\n    }\n    function format(results, docs, {\n      includeMatches = Config.includeMatches,\n      includeScore = Config.includeScore\n    } = {}) {\n      const transformers = [];\n      if (includeMatches) transformers.push(transformMatches);\n      if (includeScore) transformers.push(transformScore);\n      return results.map(result => {\n        const {\n          idx\n        } = result;\n        const data = {\n          item: docs[idx],\n          refIndex: idx\n        };\n        if (transformers.length) {\n          transformers.forEach(transformer => {\n            transformer(result, data);\n          });\n        }\n        return data;\n      });\n    }\n    class Fuse {\n      constructor(docs, options = {}, index) {\n        this.options = _objectSpread2(_objectSpread2({}, Config), options);\n        if (this.options.useExtendedSearch && true) {\n          throw new Error(EXTENDED_SEARCH_UNAVAILABLE);\n        }\n        this._keyStore = new KeyStore(this.options.keys);\n        this.setCollection(docs, index);\n      }\n      setCollection(docs, index) {\n        this._docs = docs;\n        if (index && !(index instanceof FuseIndex)) {\n          throw new Error(INCORRECT_INDEX_TYPE);\n        }\n        this._myIndex = index || createIndex(this.options.keys, this._docs, {\n          getFn: this.options.getFn,\n          fieldNormWeight: this.options.fieldNormWeight\n        });\n      }\n      add(doc) {\n        if (!isDefined(doc)) {\n          return;\n        }\n        this._docs.push(doc);\n        this._myIndex.add(doc);\n      }\n      remove(predicate = ( /* doc, idx */) => false) {\n        const results = [];\n        for (let i = 0, len = this._docs.length; i < len; i += 1) {\n          const doc = this._docs[i];\n          if (predicate(doc, i)) {\n            this.removeAt(i);\n            i -= 1;\n            len -= 1;\n            results.push(doc);\n          }\n        }\n        return results;\n      }\n      removeAt(idx) {\n        this._docs.splice(idx, 1);\n        this._myIndex.removeAt(idx);\n      }\n      getIndex() {\n        return this._myIndex;\n      }\n      search(query, {\n        limit = -1\n      } = {}) {\n        const {\n          includeMatches,\n          includeScore,\n          shouldSort,\n          sortFn,\n          ignoreFieldNorm\n        } = this.options;\n        let results = isString(query) ? isString(this._docs[0]) ? this._searchStringList(query) : this._searchObjectList(query) : this._searchLogical(query);\n        computeScore(results, {\n          ignoreFieldNorm\n        });\n        if (shouldSort) {\n          results.sort(sortFn);\n        }\n        if (isNumber(limit) && limit > -1) {\n          results = results.slice(0, limit);\n        }\n        return format(results, this._docs, {\n          includeMatches,\n          includeScore\n        });\n      }\n      _searchStringList(query) {\n        const searcher = createSearcher(query, this.options);\n        const {\n          records\n        } = this._myIndex;\n        const results = [];\n\n        // Iterate over every string in the index\n        records.forEach(({\n          v: text,\n          i: idx,\n          n: norm\n        }) => {\n          if (!isDefined(text)) {\n            return;\n          }\n          const {\n            isMatch,\n            score,\n            indices\n          } = searcher.searchIn(text);\n          if (isMatch) {\n            results.push({\n              item: text,\n              idx,\n              matches: [{\n                score,\n                value: text,\n                norm,\n                indices\n              }]\n            });\n          }\n        });\n        return results;\n      }\n      _searchLogical(query) {\n        {\n          throw new Error(LOGICAL_SEARCH_UNAVAILABLE);\n        }\n      }\n      _searchObjectList(query) {\n        const searcher = createSearcher(query, this.options);\n        const {\n          keys,\n          records\n        } = this._myIndex;\n        const results = [];\n\n        // List is Array<Object>\n        records.forEach(({\n          $: item,\n          i: idx\n        }) => {\n          if (!isDefined(item)) {\n            return;\n          }\n          let matches = [];\n\n          // Iterate over every key (i.e, path), and fetch the value at that key\n          keys.forEach((key, keyIndex) => {\n            matches.push(...this._findMatches({\n              key,\n              value: item[keyIndex],\n              searcher\n            }));\n          });\n          if (matches.length) {\n            results.push({\n              idx,\n              item,\n              matches\n            });\n          }\n        });\n        return results;\n      }\n      _findMatches({\n        key,\n        value,\n        searcher\n      }) {\n        if (!isDefined(value)) {\n          return [];\n        }\n        let matches = [];\n        if (isArray(value)) {\n          value.forEach(({\n            v: text,\n            i: idx,\n            n: norm\n          }) => {\n            if (!isDefined(text)) {\n              return;\n            }\n            const {\n              isMatch,\n              score,\n              indices\n            } = searcher.searchIn(text);\n            if (isMatch) {\n              matches.push({\n                score,\n                key,\n                value: text,\n                idx,\n                norm,\n                indices\n              });\n            }\n          });\n        } else {\n          const {\n            v: text,\n            n: norm\n          } = value;\n          const {\n            isMatch,\n            score,\n            indices\n          } = searcher.searchIn(text);\n          if (isMatch) {\n            matches.push({\n              score,\n              key,\n              value: text,\n              norm,\n              indices\n            });\n          }\n        }\n        return matches;\n      }\n    }\n    Fuse.version = '7.0.0';\n    Fuse.createIndex = createIndex;\n    Fuse.parseIndex = parseIndex;\n    Fuse.config = Config;\n    {\n      Fuse.parseQuery = parse;\n    }\n\n    var SearchByFuse = /** @class */ (function () {\n        function SearchByFuse(config) {\n            this._haystack = [];\n            this._fuseOptions = __assign(__assign({}, config.fuseOptions), { keys: __spreadArray([], config.searchFields, true), includeMatches: true });\n        }\n        SearchByFuse.prototype.index = function (data) {\n            this._haystack = data;\n            if (this._fuse) {\n                this._fuse.setCollection(data);\n            }\n        };\n        SearchByFuse.prototype.reset = function () {\n            this._haystack = [];\n            this._fuse = undefined;\n        };\n        SearchByFuse.prototype.isEmptyIndex = function () {\n            return !this._haystack.length;\n        };\n        SearchByFuse.prototype.search = function (needle) {\n            if (!this._fuse) {\n                {\n                    this._fuse = new Fuse(this._haystack, this._fuseOptions);\n                }\n            }\n            var results = this._fuse.search(needle);\n            return results.map(function (value, i) {\n                return {\n                    item: value.item,\n                    score: value.score || 0,\n                    rank: i + 1, // If value.score is used for sorting, this can create non-stable sorts!\n                };\n            });\n        };\n        return SearchByFuse;\n    }());\n\n    function getSearcher(config) {\n        {\n            return new SearchByFuse(config);\n        }\n    }\n\n    /**\n     * Helpers to create HTML elements used by Choices\n     * Can be overridden by providing `callbackOnCreateTemplates` option.\n     * `Choices.defaults.templates` allows access to the default template methods from `callbackOnCreateTemplates`\n     */\n    var isEmptyObject = function (obj) {\n        // eslint-disable-next-line no-restricted-syntax\n        for (var prop in obj) {\n            if (Object.prototype.hasOwnProperty.call(obj, prop)) {\n                return false;\n            }\n        }\n        return true;\n    };\n    var assignCustomProperties = function (el, choice, withCustomProperties) {\n        var dataset = el.dataset;\n        var customProperties = choice.customProperties, labelClass = choice.labelClass, labelDescription = choice.labelDescription;\n        if (labelClass) {\n            dataset.labelClass = getClassNames(labelClass).join(' ');\n        }\n        if (labelDescription) {\n            dataset.labelDescription = unwrapStringForRaw(labelDescription);\n        }\n        if (withCustomProperties && customProperties) {\n            if (typeof customProperties === 'string') {\n                dataset.customProperties = customProperties;\n            }\n            else if (typeof customProperties === 'object' && !isEmptyObject(customProperties)) {\n                dataset.customProperties = JSON.stringify(customProperties);\n            }\n        }\n    };\n    var addAriaLabel = function (docRoot, id, element) {\n        var label = id && docRoot.querySelector(\"label[for='\".concat(id, \"']\"));\n        var text = label && label.innerText;\n        if (text) {\n            element.setAttribute('aria-label', text);\n        }\n    };\n    var templates = {\n        containerOuter: function (_a, dir, isSelectElement, isSelectOneElement, searchEnabled, passedElementType, labelId) {\n            var containerOuter = _a.classNames.containerOuter;\n            var div = document.createElement('div');\n            addClassesToElement(div, containerOuter);\n            div.dataset.type = passedElementType;\n            if (dir) {\n                div.dir = dir;\n            }\n            if (isSelectOneElement) {\n                div.tabIndex = 0;\n            }\n            if (isSelectElement) {\n                div.setAttribute('role', searchEnabled ? 'combobox' : 'listbox');\n                if (searchEnabled) {\n                    div.setAttribute('aria-autocomplete', 'list');\n                }\n                else if (!labelId) {\n                    addAriaLabel(this._docRoot, this.passedElement.element.id, div);\n                }\n                div.setAttribute('aria-haspopup', 'true');\n                div.setAttribute('aria-expanded', 'false');\n            }\n            if (labelId) {\n                div.setAttribute('aria-labelledby', labelId);\n            }\n            return div;\n        },\n        containerInner: function (_a) {\n            var containerInner = _a.classNames.containerInner;\n            var div = document.createElement('div');\n            addClassesToElement(div, containerInner);\n            return div;\n        },\n        itemList: function (_a, isSelectOneElement) {\n            var searchEnabled = _a.searchEnabled, _b = _a.classNames, list = _b.list, listSingle = _b.listSingle, listItems = _b.listItems;\n            var div = document.createElement('div');\n            addClassesToElement(div, list);\n            addClassesToElement(div, isSelectOneElement ? listSingle : listItems);\n            if (this._isSelectElement && searchEnabled) {\n                div.setAttribute('role', 'listbox');\n            }\n            return div;\n        },\n        placeholder: function (_a, value) {\n            var allowHTML = _a.allowHTML, placeholder = _a.classNames.placeholder;\n            var div = document.createElement('div');\n            addClassesToElement(div, placeholder);\n            setElementHtml(div, allowHTML, value);\n            return div;\n        },\n        item: function (_a, choice, removeItemButton) {\n            var allowHTML = _a.allowHTML, removeItemButtonAlignLeft = _a.removeItemButtonAlignLeft, removeItemIconText = _a.removeItemIconText, removeItemLabelText = _a.removeItemLabelText, _b = _a.classNames, item = _b.item, button = _b.button, highlightedState = _b.highlightedState, itemSelectable = _b.itemSelectable, placeholder = _b.placeholder;\n            var rawValue = unwrapStringForRaw(choice.value);\n            var div = document.createElement('div');\n            addClassesToElement(div, item);\n            if (choice.labelClass) {\n                var spanLabel = document.createElement('span');\n                setElementHtml(spanLabel, allowHTML, choice.label);\n                addClassesToElement(spanLabel, choice.labelClass);\n                div.appendChild(spanLabel);\n            }\n            else {\n                setElementHtml(div, allowHTML, choice.label);\n            }\n            div.dataset.item = '';\n            div.dataset.id = choice.id;\n            div.dataset.value = rawValue;\n            assignCustomProperties(div, choice, true);\n            if (choice.disabled || this.containerOuter.isDisabled) {\n                div.setAttribute('aria-disabled', 'true');\n            }\n            if (this._isSelectElement) {\n                div.setAttribute('aria-selected', 'true');\n                div.setAttribute('role', 'option');\n            }\n            if (choice.placeholder) {\n                addClassesToElement(div, placeholder);\n                div.dataset.placeholder = '';\n            }\n            addClassesToElement(div, choice.highlighted ? highlightedState : itemSelectable);\n            if (removeItemButton) {\n                if (choice.disabled) {\n                    removeClassesFromElement(div, itemSelectable);\n                }\n                div.dataset.deletable = '';\n                var removeButton = document.createElement('button');\n                removeButton.type = 'button';\n                addClassesToElement(removeButton, button);\n                var eventChoice = getChoiceForOutput(choice);\n                setElementHtml(removeButton, true, resolveNoticeFunction(removeItemIconText, choice.value, eventChoice));\n                var REMOVE_ITEM_LABEL = resolveNoticeFunction(removeItemLabelText, choice.value, eventChoice);\n                if (REMOVE_ITEM_LABEL) {\n                    removeButton.setAttribute('aria-label', REMOVE_ITEM_LABEL);\n                }\n                removeButton.dataset.button = '';\n                if (removeItemButtonAlignLeft) {\n                    div.insertAdjacentElement('afterbegin', removeButton);\n                }\n                else {\n                    div.appendChild(removeButton);\n                }\n            }\n            return div;\n        },\n        choiceList: function (_a, isSelectOneElement) {\n            var list = _a.classNames.list;\n            var div = document.createElement('div');\n            addClassesToElement(div, list);\n            if (!isSelectOneElement) {\n                div.setAttribute('aria-multiselectable', 'true');\n            }\n            div.setAttribute('role', 'listbox');\n            return div;\n        },\n        choiceGroup: function (_a, _b) {\n            var allowHTML = _a.allowHTML, _c = _a.classNames, group = _c.group, groupHeading = _c.groupHeading, itemDisabled = _c.itemDisabled;\n            var id = _b.id, label = _b.label, disabled = _b.disabled;\n            var rawLabel = unwrapStringForRaw(label);\n            var div = document.createElement('div');\n            addClassesToElement(div, group);\n            if (disabled) {\n                addClassesToElement(div, itemDisabled);\n            }\n            div.setAttribute('role', 'group');\n            div.dataset.group = '';\n            div.dataset.id = id;\n            div.dataset.value = rawLabel;\n            if (disabled) {\n                div.setAttribute('aria-disabled', 'true');\n            }\n            var heading = document.createElement('div');\n            addClassesToElement(heading, groupHeading);\n            setElementHtml(heading, allowHTML, label || '');\n            div.appendChild(heading);\n            return div;\n        },\n        choice: function (_a, choice, selectText, groupName) {\n            var allowHTML = _a.allowHTML, _b = _a.classNames, item = _b.item, itemChoice = _b.itemChoice, itemSelectable = _b.itemSelectable, selectedState = _b.selectedState, itemDisabled = _b.itemDisabled, description = _b.description, placeholder = _b.placeholder;\n            // eslint-disable-next-line prefer-destructuring\n            var label = choice.label;\n            var rawValue = unwrapStringForRaw(choice.value);\n            var div = document.createElement('div');\n            div.id = choice.elementId;\n            addClassesToElement(div, item);\n            addClassesToElement(div, itemChoice);\n            if (groupName && typeof label === 'string') {\n                label = escapeForTemplate(allowHTML, label);\n                label += \" (\".concat(groupName, \")\");\n                label = { trusted: label };\n            }\n            var describedBy = div;\n            if (choice.labelClass) {\n                var spanLabel = document.createElement('span');\n                setElementHtml(spanLabel, allowHTML, label);\n                addClassesToElement(spanLabel, choice.labelClass);\n                describedBy = spanLabel;\n                div.appendChild(spanLabel);\n            }\n            else {\n                setElementHtml(div, allowHTML, label);\n            }\n            if (choice.labelDescription) {\n                var descId = \"\".concat(choice.elementId, \"-description\");\n                describedBy.setAttribute('aria-describedby', descId);\n                var spanDesc = document.createElement('span');\n                setElementHtml(spanDesc, allowHTML, choice.labelDescription);\n                spanDesc.id = descId;\n                addClassesToElement(spanDesc, description);\n                div.appendChild(spanDesc);\n            }\n            if (choice.selected) {\n                addClassesToElement(div, selectedState);\n            }\n            if (choice.placeholder) {\n                addClassesToElement(div, placeholder);\n            }\n            div.setAttribute('role', choice.group ? 'treeitem' : 'option');\n            div.dataset.choice = '';\n            div.dataset.id = choice.id;\n            div.dataset.value = rawValue;\n            if (selectText) {\n                div.dataset.selectText = selectText;\n            }\n            if (choice.group) {\n                div.dataset.groupId = \"\".concat(choice.group.id);\n            }\n            assignCustomProperties(div, choice, false);\n            if (choice.disabled) {\n                addClassesToElement(div, itemDisabled);\n                div.dataset.choiceDisabled = '';\n                div.setAttribute('aria-disabled', 'true');\n            }\n            else {\n                addClassesToElement(div, itemSelectable);\n                div.dataset.choiceSelectable = '';\n                div.setAttribute('aria-selected', choice.selected ? 'true' : 'false');\n            }\n            return div;\n        },\n        input: function (_a, placeholderValue) {\n            var _b = _a.classNames, input = _b.input, inputCloned = _b.inputCloned, labelId = _a.labelId;\n            var inp = document.createElement('input');\n            inp.type = 'search';\n            addClassesToElement(inp, input);\n            addClassesToElement(inp, inputCloned);\n            inp.autocomplete = 'off';\n            inp.autocapitalize = 'off';\n            inp.spellcheck = false;\n            inp.setAttribute('aria-autocomplete', 'list');\n            if (placeholderValue) {\n                inp.setAttribute('aria-label', placeholderValue);\n            }\n            else if (!labelId) {\n                addAriaLabel(this._docRoot, this.passedElement.element.id, inp);\n            }\n            return inp;\n        },\n        dropdown: function (_a) {\n            var _b = _a.classNames, list = _b.list, listDropdown = _b.listDropdown;\n            var div = document.createElement('div');\n            addClassesToElement(div, list);\n            addClassesToElement(div, listDropdown);\n            div.setAttribute('aria-expanded', 'false');\n            return div;\n        },\n        notice: function (_a, innerHTML, type) {\n            var _b = _a.classNames, item = _b.item, itemChoice = _b.itemChoice, addChoice = _b.addChoice, noResults = _b.noResults, noChoices = _b.noChoices, noticeItem = _b.notice;\n            if (type === void 0) { type = NoticeTypes.generic; }\n            var notice = document.createElement('div');\n            setElementHtml(notice, true, innerHTML);\n            addClassesToElement(notice, item);\n            addClassesToElement(notice, itemChoice);\n            addClassesToElement(notice, noticeItem);\n            // eslint-disable-next-line default-case\n            switch (type) {\n                case NoticeTypes.addChoice:\n                    addClassesToElement(notice, addChoice);\n                    break;\n                case NoticeTypes.noResults:\n                    addClassesToElement(notice, noResults);\n                    break;\n                case NoticeTypes.noChoices:\n                    addClassesToElement(notice, noChoices);\n                    break;\n            }\n            if (type === NoticeTypes.addChoice) {\n                notice.dataset.choiceSelectable = '';\n                notice.dataset.choice = '';\n            }\n            return notice;\n        },\n        option: function (choice) {\n            // HtmlOptionElement's label value does not support HTML, so the avoid double escaping unwrap the untrusted string.\n            var labelValue = unwrapStringForRaw(choice.label);\n            var opt = new Option(labelValue, choice.value, false, choice.selected);\n            assignCustomProperties(opt, choice, true);\n            opt.disabled = choice.disabled;\n            if (choice.selected) {\n                opt.setAttribute('selected', '');\n            }\n            return opt;\n        },\n    };\n\n    /** @see {@link http://browserhacks.com/#hack-acea075d0ac6954f275a70023906050c} */\n    var IS_IE11 = '-ms-scroll-limit' in document.documentElement.style &&\n        '-ms-ime-align' in document.documentElement.style;\n    var USER_DEFAULTS = {};\n    var parseDataSetId = function (element) {\n        if (!element) {\n            return undefined;\n        }\n        return element.dataset.id ? parseInt(element.dataset.id, 10) : undefined;\n    };\n    var selectableChoiceIdentifier = '[data-choice-selectable]';\n    /**\n     * Choices\n     * @author Josh Johnson<josh@joshuajohnson.co.uk>\n     */\n    var Choices = /** @class */ (function () {\n        function Choices(element, userConfig) {\n            if (element === void 0) { element = '[data-choice]'; }\n            if (userConfig === void 0) { userConfig = {}; }\n            var _this = this;\n            this.initialisedOK = undefined;\n            this._hasNonChoicePlaceholder = false;\n            this._lastAddedChoiceId = 0;\n            this._lastAddedGroupId = 0;\n            var defaults = Choices.defaults;\n            this.config = __assign(__assign(__assign({}, defaults.allOptions), defaults.options), userConfig);\n            ObjectsInConfig.forEach(function (key) {\n                _this.config[key] = __assign(__assign(__assign({}, defaults.allOptions[key]), defaults.options[key]), userConfig[key]);\n            });\n            var config = this.config;\n            if (!config.silent) {\n                this._validateConfig();\n            }\n            var docRoot = config.shadowRoot || document.documentElement;\n            this._docRoot = docRoot;\n            var passedElement = typeof element === 'string' ? docRoot.querySelector(element) : element;\n            if (!passedElement ||\n                typeof passedElement !== 'object' ||\n                !(isHtmlInputElement(passedElement) || isHtmlSelectElement(passedElement))) {\n                if (!passedElement && typeof element === 'string') {\n                    throw TypeError(\"Selector \".concat(element, \" failed to find an element\"));\n                }\n                throw TypeError(\"Expected one of the following types text|select-one|select-multiple\");\n            }\n            var elementType = passedElement.type;\n            var isText = elementType === PassedElementTypes.Text;\n            if (isText || config.maxItemCount !== 1) {\n                config.singleModeForMultiSelect = false;\n            }\n            if (config.singleModeForMultiSelect) {\n                elementType = PassedElementTypes.SelectMultiple;\n            }\n            var isSelectOne = elementType === PassedElementTypes.SelectOne;\n            var isSelectMultiple = elementType === PassedElementTypes.SelectMultiple;\n            var isSelect = isSelectOne || isSelectMultiple;\n            this._elementType = elementType;\n            this._isTextElement = isText;\n            this._isSelectOneElement = isSelectOne;\n            this._isSelectMultipleElement = isSelectMultiple;\n            this._isSelectElement = isSelectOne || isSelectMultiple;\n            this._canAddUserChoices = (isText && config.addItems) || (isSelect && config.addChoices);\n            if (typeof config.renderSelectedChoices !== 'boolean') {\n                config.renderSelectedChoices = config.renderSelectedChoices === 'always' || isSelectOne;\n            }\n            if (config.closeDropdownOnSelect === 'auto') {\n                config.closeDropdownOnSelect = isText || isSelectOne || config.singleModeForMultiSelect;\n            }\n            else {\n                config.closeDropdownOnSelect = coerceBool(config.closeDropdownOnSelect);\n            }\n            if (config.placeholder) {\n                if (config.placeholderValue) {\n                    this._hasNonChoicePlaceholder = true;\n                }\n                else if (passedElement.dataset.placeholder) {\n                    this._hasNonChoicePlaceholder = true;\n                    config.placeholderValue = passedElement.dataset.placeholder;\n                }\n            }\n            if (userConfig.addItemFilter && typeof userConfig.addItemFilter !== 'function') {\n                var re = userConfig.addItemFilter instanceof RegExp ? userConfig.addItemFilter : new RegExp(userConfig.addItemFilter);\n                config.addItemFilter = re.test.bind(re);\n            }\n            if (this._isTextElement) {\n                this.passedElement = new WrappedInput({\n                    element: passedElement,\n                    classNames: config.classNames,\n                });\n            }\n            else {\n                var selectEl = passedElement;\n                this.passedElement = new WrappedSelect({\n                    element: selectEl,\n                    classNames: config.classNames,\n                    template: function (data) { return _this._templates.option(data); },\n                    extractPlaceholder: config.placeholder && !this._hasNonChoicePlaceholder,\n                });\n            }\n            this.initialised = false;\n            this._store = new Store(config);\n            this._currentValue = '';\n            config.searchEnabled = !isText && config.searchEnabled;\n            this._canSearch = config.searchEnabled;\n            this._isScrollingOnIe = false;\n            this._highlightPosition = 0;\n            this._wasTap = true;\n            this._placeholderValue = this._generatePlaceholderValue();\n            this._baseId = generateId(passedElement, 'choices-');\n            /**\n             * setting direction in cases where it's explicitly set on passedElement\n             * or when calculated direction is different from the document\n             */\n            this._direction = passedElement.dir;\n            if (!this._direction) {\n                var elementDirection = window.getComputedStyle(passedElement).direction;\n                var documentDirection = window.getComputedStyle(document.documentElement).direction;\n                if (elementDirection !== documentDirection) {\n                    this._direction = elementDirection;\n                }\n            }\n            this._idNames = {\n                itemChoice: 'item-choice',\n            };\n            this._templates = defaults.templates;\n            this._render = this._render.bind(this);\n            this._onFocus = this._onFocus.bind(this);\n            this._onBlur = this._onBlur.bind(this);\n            this._onKeyUp = this._onKeyUp.bind(this);\n            this._onKeyDown = this._onKeyDown.bind(this);\n            this._onInput = this._onInput.bind(this);\n            this._onClick = this._onClick.bind(this);\n            this._onTouchMove = this._onTouchMove.bind(this);\n            this._onTouchEnd = this._onTouchEnd.bind(this);\n            this._onMouseDown = this._onMouseDown.bind(this);\n            this._onMouseOver = this._onMouseOver.bind(this);\n            this._onFormReset = this._onFormReset.bind(this);\n            this._onSelectKey = this._onSelectKey.bind(this);\n            this._onEnterKey = this._onEnterKey.bind(this);\n            this._onEscapeKey = this._onEscapeKey.bind(this);\n            this._onDirectionKey = this._onDirectionKey.bind(this);\n            this._onDeleteKey = this._onDeleteKey.bind(this);\n            this._onChange = this._onChange.bind(this);\n            this._onInvalid = this._onInvalid.bind(this);\n            // If element has already been initialised with Choices, fail silently\n            if (this.passedElement.isActive) {\n                if (!config.silent) {\n                    console.warn('Trying to initialise Choices on element already initialised', { element: element });\n                }\n                this.initialised = true;\n                this.initialisedOK = false;\n                return;\n            }\n            // Let's go\n            this.init();\n            // preserve the selected item list after setup for form reset\n            this._initialItems = this._store.items.map(function (choice) { return choice.value; });\n        }\n        Object.defineProperty(Choices, \"defaults\", {\n            get: function () {\n                return Object.preventExtensions({\n                    get options() {\n                        return USER_DEFAULTS;\n                    },\n                    get allOptions() {\n                        return DEFAULT_CONFIG;\n                    },\n                    get templates() {\n                        return templates;\n                    },\n                });\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Choices.prototype.init = function () {\n            if (this.initialised || this.initialisedOK !== undefined) {\n                return;\n            }\n            this._searcher = getSearcher(this.config);\n            this._loadChoices();\n            this._createTemplates();\n            this._createElements();\n            this._createStructure();\n            if ((this._isTextElement && !this.config.addItems) ||\n                this.passedElement.element.hasAttribute('disabled') ||\n                !!this.passedElement.element.closest('fieldset:disabled')) {\n                this.disable();\n            }\n            else {\n                this.enable();\n                this._addEventListeners();\n            }\n            // should be triggered **after** disabled state to avoid additional re-draws\n            this._initStore();\n            this.initialised = true;\n            this.initialisedOK = true;\n            var callbackOnInit = this.config.callbackOnInit;\n            // Run callback if it is a function\n            if (typeof callbackOnInit === 'function') {\n                callbackOnInit.call(this);\n            }\n        };\n        Choices.prototype.destroy = function () {\n            if (!this.initialised) {\n                return;\n            }\n            this._removeEventListeners();\n            this.passedElement.reveal();\n            this.containerOuter.unwrap(this.passedElement.element);\n            this._store._listeners = []; // prevents select/input value being wiped\n            this.clearStore(false);\n            this._stopSearch();\n            this._templates = Choices.defaults.templates;\n            this.initialised = false;\n            this.initialisedOK = undefined;\n        };\n        Choices.prototype.enable = function () {\n            if (this.passedElement.isDisabled) {\n                this.passedElement.enable();\n            }\n            if (this.containerOuter.isDisabled) {\n                this._addEventListeners();\n                this.input.enable();\n                this.containerOuter.enable();\n            }\n            return this;\n        };\n        Choices.prototype.disable = function () {\n            if (!this.passedElement.isDisabled) {\n                this.passedElement.disable();\n            }\n            if (!this.containerOuter.isDisabled) {\n                this._removeEventListeners();\n                this.input.disable();\n                this.containerOuter.disable();\n            }\n            return this;\n        };\n        Choices.prototype.highlightItem = function (item, runEvent) {\n            if (runEvent === void 0) { runEvent = true; }\n            if (!item || !item.id) {\n                return this;\n            }\n            var choice = this._store.items.find(function (c) { return c.id === item.id; });\n            if (!choice || choice.highlighted) {\n                return this;\n            }\n            this._store.dispatch(highlightItem(choice, true));\n            if (runEvent) {\n                this.passedElement.triggerEvent(EventType.highlightItem, getChoiceForOutput(choice));\n            }\n            return this;\n        };\n        Choices.prototype.unhighlightItem = function (item, runEvent) {\n            if (runEvent === void 0) { runEvent = true; }\n            if (!item || !item.id) {\n                return this;\n            }\n            var choice = this._store.items.find(function (c) { return c.id === item.id; });\n            if (!choice || !choice.highlighted) {\n                return this;\n            }\n            this._store.dispatch(highlightItem(choice, false));\n            if (runEvent) {\n                this.passedElement.triggerEvent(EventType.unhighlightItem, getChoiceForOutput(choice));\n            }\n            return this;\n        };\n        Choices.prototype.highlightAll = function () {\n            var _this = this;\n            this._store.withTxn(function () {\n                _this._store.items.forEach(function (item) {\n                    if (!item.highlighted) {\n                        _this._store.dispatch(highlightItem(item, true));\n                        _this.passedElement.triggerEvent(EventType.highlightItem, getChoiceForOutput(item));\n                    }\n                });\n            });\n            return this;\n        };\n        Choices.prototype.unhighlightAll = function () {\n            var _this = this;\n            this._store.withTxn(function () {\n                _this._store.items.forEach(function (item) {\n                    if (item.highlighted) {\n                        _this._store.dispatch(highlightItem(item, false));\n                        _this.passedElement.triggerEvent(EventType.highlightItem, getChoiceForOutput(item));\n                    }\n                });\n            });\n            return this;\n        };\n        Choices.prototype.removeActiveItemsByValue = function (value) {\n            var _this = this;\n            this._store.withTxn(function () {\n                _this._store.items.filter(function (item) { return item.value === value; }).forEach(function (item) { return _this._removeItem(item); });\n            });\n            return this;\n        };\n        Choices.prototype.removeActiveItems = function (excludedId) {\n            var _this = this;\n            this._store.withTxn(function () {\n                _this._store.items.filter(function (_a) {\n                    var id = _a.id;\n                    return id !== excludedId;\n                }).forEach(function (item) { return _this._removeItem(item); });\n            });\n            return this;\n        };\n        Choices.prototype.removeHighlightedItems = function (runEvent) {\n            var _this = this;\n            if (runEvent === void 0) { runEvent = false; }\n            this._store.withTxn(function () {\n                _this._store.highlightedActiveItems.forEach(function (item) {\n                    _this._removeItem(item);\n                    // If this action was performed by the user\n                    // trigger the event\n                    if (runEvent) {\n                        _this._triggerChange(item.value);\n                    }\n                });\n            });\n            return this;\n        };\n        Choices.prototype.showDropdown = function (preventInputFocus) {\n            var _this = this;\n            if (this.dropdown.isActive) {\n                return this;\n            }\n            if (preventInputFocus === undefined) {\n                // eslint-disable-next-line no-param-reassign\n                preventInputFocus = !this._canSearch;\n            }\n            requestAnimationFrame(function () {\n                _this.dropdown.show();\n                var rect = _this.dropdown.element.getBoundingClientRect();\n                _this.containerOuter.open(rect.bottom, rect.height);\n                if (!preventInputFocus) {\n                    _this.input.focus();\n                }\n                _this.passedElement.triggerEvent(EventType.showDropdown);\n                var activeElement = _this.choiceList.element.querySelector(getClassNamesSelector(_this.config.classNames.selectedState));\n                if (activeElement !== null && !isScrolledIntoView(activeElement, _this.choiceList.element)) {\n                    // We use the native scrollIntoView function instead of choiceList.scrollToChildElement to avoid animated scroll.\n                    activeElement.scrollIntoView();\n                }\n            });\n            return this;\n        };\n        Choices.prototype.hideDropdown = function (preventInputBlur) {\n            var _this = this;\n            if (!this.dropdown.isActive) {\n                return this;\n            }\n            this._removeHighlightedChoices();\n            requestAnimationFrame(function () {\n                _this.dropdown.hide();\n                _this.containerOuter.close();\n                if (!preventInputBlur && _this._canSearch) {\n                    _this.input.removeActiveDescendant();\n                    _this.input.blur();\n                }\n                _this.passedElement.triggerEvent(EventType.hideDropdown);\n            });\n            return this;\n        };\n        Choices.prototype.getValue = function (valueOnly) {\n            var values = this._store.items.map(function (item) {\n                return (valueOnly ? item.value : getChoiceForOutput(item));\n            });\n            return this._isSelectOneElement || this.config.singleModeForMultiSelect ? values[0] : values;\n        };\n        Choices.prototype.setValue = function (items) {\n            var _this = this;\n            if (!this.initialisedOK) {\n                this._warnChoicesInitFailed('setValue');\n                return this;\n            }\n            this._store.withTxn(function () {\n                items.forEach(function (value) {\n                    if (value) {\n                        _this._addChoice(mapInputToChoice(value, false));\n                    }\n                });\n            });\n            // @todo integrate with Store\n            this._searcher.reset();\n            return this;\n        };\n        Choices.prototype.setChoiceByValue = function (value) {\n            var _this = this;\n            if (!this.initialisedOK) {\n                this._warnChoicesInitFailed('setChoiceByValue');\n                return this;\n            }\n            if (this._isTextElement) {\n                return this;\n            }\n            this._store.withTxn(function () {\n                // If only one value has been passed, convert to array\n                var choiceValue = Array.isArray(value) ? value : [value];\n                // Loop through each value and\n                choiceValue.forEach(function (val) { return _this._findAndSelectChoiceByValue(val); });\n                _this.unhighlightAll();\n            });\n            // @todo integrate with Store\n            this._searcher.reset();\n            return this;\n        };\n        /**\n         * Set choices of select input via an array of objects (or function that returns array of object or promise of it),\n         * a value field name and a label field name.\n         * This behaves the same as passing items via the choices option but can be called after initialising Choices.\n         * This can also be used to add groups of choices (see example 2); Optionally pass a true `replaceChoices` value to remove any existing choices.\n         * Optionally pass a `customProperties` object to add additional data to your choices (useful when searching/filtering etc).\n         *\n         * **Input types affected:** select-one, select-multiple\n         *\n         * @example\n         * ```js\n         * const example = new Choices(element);\n         *\n         * example.setChoices([\n         *   {value: 'One', label: 'Label One', disabled: true},\n         *   {value: 'Two', label: 'Label Two', selected: true},\n         *   {value: 'Three', label: 'Label Three'},\n         * ], 'value', 'label', false);\n         * ```\n         *\n         * @example\n         * ```js\n         * const example = new Choices(element);\n         *\n         * example.setChoices(async () => {\n         *   try {\n         *      const items = await fetch('/items');\n         *      return items.json()\n         *   } catch(err) {\n         *      console.error(err)\n         *   }\n         * });\n         * ```\n         *\n         * @example\n         * ```js\n         * const example = new Choices(element);\n         *\n         * example.setChoices([{\n         *   label: 'Group one',\n         *   id: 1,\n         *   disabled: false,\n         *   choices: [\n         *     {value: 'Child One', label: 'Child One', selected: true},\n         *     {value: 'Child Two', label: 'Child Two',  disabled: true},\n         *     {value: 'Child Three', label: 'Child Three'},\n         *   ]\n         * },\n         * {\n         *   label: 'Group two',\n         *   id: 2,\n         *   disabled: false,\n         *   choices: [\n         *     {value: 'Child Four', label: 'Child Four', disabled: true},\n         *     {value: 'Child Five', label: 'Child Five'},\n         *     {value: 'Child Six', label: 'Child Six', customProperties: {\n         *       description: 'Custom description about child six',\n         *       random: 'Another random custom property'\n         *     }},\n         *   ]\n         * }], 'value', 'label', false);\n         * ```\n         */\n        Choices.prototype.setChoices = function (choicesArrayOrFetcher, value, label, replaceChoices, clearSearchFlag, replaceItems) {\n            var _this = this;\n            if (choicesArrayOrFetcher === void 0) { choicesArrayOrFetcher = []; }\n            if (value === void 0) { value = 'value'; }\n            if (label === void 0) { label = 'label'; }\n            if (replaceChoices === void 0) { replaceChoices = false; }\n            if (clearSearchFlag === void 0) { clearSearchFlag = true; }\n            if (replaceItems === void 0) { replaceItems = false; }\n            if (!this.initialisedOK) {\n                this._warnChoicesInitFailed('setChoices');\n                return this;\n            }\n            if (!this._isSelectElement) {\n                throw new TypeError(\"setChoices can't be used with INPUT based Choices\");\n            }\n            if (typeof value !== 'string' || !value) {\n                throw new TypeError(\"value parameter must be a name of 'value' field in passed objects\");\n            }\n            if (typeof choicesArrayOrFetcher === 'function') {\n                // it's a choices fetcher function\n                var fetcher_1 = choicesArrayOrFetcher(this);\n                if (typeof Promise === 'function' && fetcher_1 instanceof Promise) {\n                    // that's a promise\n                    // eslint-disable-next-line no-promise-executor-return\n                    return new Promise(function (resolve) { return requestAnimationFrame(resolve); })\n                        .then(function () { return _this._handleLoadingState(true); })\n                        .then(function () { return fetcher_1; })\n                        .then(function (data) {\n                        return _this.setChoices(data, value, label, replaceChoices, clearSearchFlag, replaceItems);\n                    })\n                        .catch(function (err) {\n                        if (!_this.config.silent) {\n                            console.error(err);\n                        }\n                    })\n                        .then(function () { return _this._handleLoadingState(false); })\n                        .then(function () { return _this; });\n                }\n                // function returned something else than promise, let's check if it's an array of choices\n                if (!Array.isArray(fetcher_1)) {\n                    throw new TypeError(\".setChoices first argument function must return either array of choices or Promise, got: \".concat(typeof fetcher_1));\n                }\n                // recursion with results, it's sync and choices were cleared already\n                return this.setChoices(fetcher_1, value, label, false);\n            }\n            if (!Array.isArray(choicesArrayOrFetcher)) {\n                throw new TypeError(\".setChoices must be called either with array of choices with a function resulting into Promise of array of choices\");\n            }\n            this.containerOuter.removeLoadingState();\n            this._store.withTxn(function () {\n                if (clearSearchFlag) {\n                    _this._isSearching = false;\n                }\n                // Clear choices if needed\n                if (replaceChoices) {\n                    _this.clearChoices(true, replaceItems);\n                }\n                var isDefaultValue = value === 'value';\n                var isDefaultLabel = label === 'label';\n                choicesArrayOrFetcher.forEach(function (groupOrChoice) {\n                    if ('choices' in groupOrChoice) {\n                        var group = groupOrChoice;\n                        if (!isDefaultLabel) {\n                            group = __assign(__assign({}, group), { label: group[label] });\n                        }\n                        _this._addGroup(mapInputToChoice(group, true));\n                    }\n                    else {\n                        var choice = groupOrChoice;\n                        if (!isDefaultLabel || !isDefaultValue) {\n                            choice = __assign(__assign({}, choice), { value: choice[value], label: choice[label] });\n                        }\n                        var choiceFull = mapInputToChoice(choice, false);\n                        _this._addChoice(choiceFull);\n                        if (choiceFull.placeholder && !_this._hasNonChoicePlaceholder) {\n                            _this._placeholderValue = unwrapStringForEscaped(choiceFull.label);\n                        }\n                    }\n                });\n                _this.unhighlightAll();\n            });\n            // @todo integrate with Store\n            this._searcher.reset();\n            return this;\n        };\n        Choices.prototype.refresh = function (withEvents, selectFirstOption, deselectAll) {\n            var _this = this;\n            if (withEvents === void 0) { withEvents = false; }\n            if (selectFirstOption === void 0) { selectFirstOption = false; }\n            if (deselectAll === void 0) { deselectAll = false; }\n            if (!this._isSelectElement) {\n                if (!this.config.silent) {\n                    console.warn('refresh method can only be used on choices backed by a <select> element');\n                }\n                return this;\n            }\n            this._store.withTxn(function () {\n                var choicesFromOptions = _this.passedElement.optionsAsChoices();\n                // Build the list of items which require preserving\n                var existingItems = {};\n                if (!deselectAll) {\n                    _this._store.items.forEach(function (choice) {\n                        if (choice.id && choice.active && choice.selected) {\n                            existingItems[choice.value] = true;\n                        }\n                    });\n                }\n                _this.clearStore(false);\n                var updateChoice = function (choice) {\n                    if (deselectAll) {\n                        _this._store.dispatch(removeItem$1(choice));\n                    }\n                    else if (existingItems[choice.value]) {\n                        choice.selected = true;\n                    }\n                };\n                choicesFromOptions.forEach(function (groupOrChoice) {\n                    if ('choices' in groupOrChoice) {\n                        groupOrChoice.choices.forEach(updateChoice);\n                        return;\n                    }\n                    updateChoice(groupOrChoice);\n                });\n                /* @todo only generate add events for the added options instead of all\n                if (withEvents) {\n                  items.forEach((choice) => {\n                    if (existingItems[choice.value]) {\n                      this.passedElement.triggerEvent(\n                        EventType.removeItem,\n                        this._getChoiceForEvent(choice),\n                      );\n                    }\n                  });\n                }\n                */\n                // load new choices & items\n                _this._addPredefinedChoices(choicesFromOptions, selectFirstOption, withEvents);\n                // re-do search if required\n                if (_this._isSearching) {\n                    _this._searchChoices(_this.input.value);\n                }\n            });\n            return this;\n        };\n        Choices.prototype.removeChoice = function (value) {\n            var choice = this._store.choices.find(function (c) { return c.value === value; });\n            if (!choice) {\n                return this;\n            }\n            this._clearNotice();\n            this._store.dispatch(removeChoice(choice));\n            // @todo integrate with Store\n            this._searcher.reset();\n            if (choice.selected) {\n                this.passedElement.triggerEvent(EventType.removeItem, getChoiceForOutput(choice));\n            }\n            return this;\n        };\n        Choices.prototype.clearChoices = function (clearOptions, clearItems) {\n            var _this = this;\n            if (clearOptions === void 0) { clearOptions = true; }\n            if (clearItems === void 0) { clearItems = false; }\n            if (clearOptions) {\n                if (clearItems) {\n                    this.passedElement.element.replaceChildren('');\n                }\n                else {\n                    this.passedElement.element.querySelectorAll(':not([selected])').forEach(function (el) {\n                        el.remove();\n                    });\n                }\n            }\n            this.itemList.element.replaceChildren('');\n            this.choiceList.element.replaceChildren('');\n            this._clearNotice();\n            this._store.withTxn(function () {\n                var items = clearItems ? [] : _this._store.items;\n                _this._store.reset();\n                items.forEach(function (item) {\n                    _this._store.dispatch(addChoice(item));\n                    _this._store.dispatch(addItem(item));\n                });\n            });\n            // @todo integrate with Store\n            this._searcher.reset();\n            return this;\n        };\n        Choices.prototype.clearStore = function (clearOptions) {\n            if (clearOptions === void 0) { clearOptions = true; }\n            this.clearChoices(clearOptions, true);\n            this._stopSearch();\n            this._lastAddedChoiceId = 0;\n            this._lastAddedGroupId = 0;\n            return this;\n        };\n        Choices.prototype.clearInput = function () {\n            var shouldSetInputWidth = !this._isSelectOneElement;\n            this.input.clear(shouldSetInputWidth);\n            this._stopSearch();\n            return this;\n        };\n        Choices.prototype._validateConfig = function () {\n            var config = this.config;\n            var invalidConfigOptions = diff(config, DEFAULT_CONFIG);\n            if (invalidConfigOptions.length) {\n                console.warn('Unknown config option(s) passed', invalidConfigOptions.join(', '));\n            }\n            if (config.allowHTML && config.allowHtmlUserInput) {\n                if (config.addItems) {\n                    console.warn('Warning: allowHTML/allowHtmlUserInput/addItems all being true is strongly not recommended and may lead to XSS attacks');\n                }\n                if (config.addChoices) {\n                    console.warn('Warning: allowHTML/allowHtmlUserInput/addChoices all being true is strongly not recommended and may lead to XSS attacks');\n                }\n            }\n        };\n        Choices.prototype._render = function (changes) {\n            if (changes === void 0) { changes = { choices: true, groups: true, items: true }; }\n            if (this._store.inTxn()) {\n                return;\n            }\n            if (this._isSelectElement) {\n                if (changes.choices || changes.groups) {\n                    this._renderChoices();\n                }\n            }\n            if (changes.items) {\n                this._renderItems();\n            }\n        };\n        Choices.prototype._renderChoices = function () {\n            var _this = this;\n            if (!this._canAddItems()) {\n                return; // block rendering choices if the input limit is reached.\n            }\n            var _a = this, config = _a.config, isSearching = _a._isSearching;\n            var _b = this._store, activeGroups = _b.activeGroups, activeChoices = _b.activeChoices;\n            var renderLimit = isSearching ? config.searchResultLimit : config.renderChoiceLimit;\n            if (this._isSelectElement) {\n                var backingOptions = activeChoices.filter(function (choice) { return !choice.element; });\n                if (backingOptions.length) {\n                    this.passedElement.addOptions(backingOptions);\n                }\n            }\n            var fragment = document.createDocumentFragment();\n            var renderableChoices = function (choices) {\n                return choices.filter(function (choice) {\n                    return !choice.placeholder &&\n                        (isSearching\n                            ? (config.searchRenderSelectedChoices || !choice.selected) && !!choice.rank\n                            : config.renderSelectedChoices || !choice.selected);\n                });\n            };\n            var showLabel = config.appendGroupInSearch && isSearching;\n            var selectableChoices = false;\n            var highlightedEl = null;\n            var renderChoices = function (choices, withinGroup) {\n                if (isSearching) {\n                    // sortByRank is used to ensure stable sorting, as scores are non-unique\n                    // this additionally ensures fuseOptions.sortFn is not ignored\n                    choices.sort(sortByRank);\n                }\n                else if (config.shouldSort) {\n                    choices.sort(config.sorter);\n                }\n                var choiceLimit = choices.length;\n                choiceLimit = !withinGroup && renderLimit > 0 && choiceLimit > renderLimit ? renderLimit : choiceLimit;\n                choiceLimit--;\n                choices.every(function (choice, index) {\n                    // choiceEl being empty signals the contents has probably significantly changed\n                    var dropdownItem = choice.choiceEl ||\n                        _this._templates.choice(config, choice, config.itemSelectText, showLabel && choice.group ? choice.group.label : undefined);\n                    choice.choiceEl = dropdownItem;\n                    fragment.appendChild(dropdownItem);\n                    if (isSearching || !choice.selected) {\n                        selectableChoices = true;\n                    }\n                    else if (!highlightedEl) {\n                        highlightedEl = dropdownItem;\n                    }\n                    return index < choiceLimit;\n                });\n            };\n            if (activeChoices.length) {\n                if (config.resetScrollPosition) {\n                    requestAnimationFrame(function () { return _this.choiceList.scrollToTop(); });\n                }\n                if (!this._hasNonChoicePlaceholder && !isSearching && this._isSelectOneElement) {\n                    // If we have a placeholder choice along with groups\n                    renderChoices(activeChoices.filter(function (choice) { return choice.placeholder && !choice.group; }), false);\n                }\n                // If we have grouped options\n                if (activeGroups.length && !isSearching) {\n                    if (config.shouldSort) {\n                        activeGroups.sort(config.sorter);\n                    }\n                    // render Choices without group first, regardless of sort, otherwise they won't be distinguishable\n                    // from the last group\n                    renderChoices(activeChoices.filter(function (choice) { return !choice.placeholder && !choice.group; }), false);\n                    activeGroups.forEach(function (group) {\n                        var groupChoices = renderableChoices(group.choices);\n                        if (groupChoices.length) {\n                            if (group.label) {\n                                var dropdownGroup = group.groupEl || _this._templates.choiceGroup(_this.config, group);\n                                group.groupEl = dropdownGroup;\n                                dropdownGroup.remove();\n                                fragment.appendChild(dropdownGroup);\n                            }\n                            renderChoices(groupChoices, true);\n                        }\n                    });\n                }\n                else {\n                    renderChoices(renderableChoices(activeChoices), false);\n                }\n            }\n            if (!selectableChoices && (isSearching || !fragment.children.length || !config.renderSelectedChoices)) {\n                if (!this._notice) {\n                    this._notice = {\n                        text: resolveStringFunction(isSearching ? config.noResultsText : config.noChoicesText),\n                        type: isSearching ? NoticeTypes.noResults : NoticeTypes.noChoices,\n                    };\n                }\n                fragment.replaceChildren('');\n            }\n            this._renderNotice(fragment);\n            this.choiceList.element.replaceChildren(fragment);\n            this._highlightChoice(highlightedEl);\n        };\n        Choices.prototype._renderItems = function () {\n            var _this = this;\n            var items = this._store.items || [];\n            var itemList = this.itemList.element;\n            var config = this.config;\n            var fragment = document.createDocumentFragment();\n            var itemFromList = function (item) {\n                return itemList.querySelector(\"[data-item][data-id=\\\"\".concat(item.id, \"\\\"]\"));\n            };\n            var addItemToFragment = function (item) {\n                var el = item.itemEl;\n                if (el && el.parentElement) {\n                    return;\n                }\n                el = itemFromList(item) || _this._templates.item(config, item, config.removeItemButton);\n                item.itemEl = el;\n                fragment.appendChild(el);\n            };\n            // new items\n            items.forEach(addItemToFragment);\n            var addedItems = !!fragment.childNodes.length;\n            if (this._isSelectOneElement) {\n                var existingItems = itemList.children.length;\n                if (addedItems || existingItems > 1) {\n                    var placeholder = itemList.querySelector(getClassNamesSelector(config.classNames.placeholder));\n                    if (placeholder) {\n                        placeholder.remove();\n                    }\n                }\n                else if (!addedItems && !existingItems && this._placeholderValue) {\n                    addedItems = true;\n                    addItemToFragment(mapInputToChoice({\n                        selected: true,\n                        value: '',\n                        label: this._placeholderValue,\n                        placeholder: true,\n                    }, false));\n                }\n            }\n            if (addedItems) {\n                itemList.append(fragment);\n                if (config.shouldSortItems && !this._isSelectOneElement) {\n                    items.sort(config.sorter);\n                    // push sorting into the DOM\n                    items.forEach(function (item) {\n                        var el = itemFromList(item);\n                        if (el) {\n                            el.remove();\n                            fragment.append(el);\n                        }\n                    });\n                    itemList.append(fragment);\n                }\n            }\n            if (this._isTextElement) {\n                // Update the value of the hidden input\n                this.passedElement.value = items.map(function (_a) {\n                    var value = _a.value;\n                    return value;\n                }).join(config.delimiter);\n            }\n        };\n        Choices.prototype._displayNotice = function (text, type, openDropdown) {\n            if (openDropdown === void 0) { openDropdown = true; }\n            var oldNotice = this._notice;\n            if (oldNotice &&\n                ((oldNotice.type === type && oldNotice.text === text) ||\n                    (oldNotice.type === NoticeTypes.addChoice &&\n                        (type === NoticeTypes.noResults || type === NoticeTypes.noChoices)))) {\n                if (openDropdown) {\n                    this.showDropdown(true);\n                }\n                return;\n            }\n            this._clearNotice();\n            this._notice = text\n                ? {\n                    text: text,\n                    type: type,\n                }\n                : undefined;\n            this._renderNotice();\n            if (openDropdown && text) {\n                this.showDropdown(true);\n            }\n        };\n        Choices.prototype._clearNotice = function () {\n            if (!this._notice) {\n                return;\n            }\n            var noticeElement = this.choiceList.element.querySelector(getClassNamesSelector(this.config.classNames.notice));\n            if (noticeElement) {\n                noticeElement.remove();\n            }\n            this._notice = undefined;\n        };\n        Choices.prototype._renderNotice = function (fragment) {\n            var noticeConf = this._notice;\n            if (noticeConf) {\n                var notice = this._templates.notice(this.config, noticeConf.text, noticeConf.type);\n                if (fragment) {\n                    fragment.append(notice);\n                }\n                else {\n                    this.choiceList.prepend(notice);\n                }\n            }\n        };\n        /**\n         * @deprecated Use utils.getChoiceForOutput\n         */\n        // eslint-disable-next-line class-methods-use-this\n        Choices.prototype._getChoiceForOutput = function (choice, keyCode) {\n            return getChoiceForOutput(choice, keyCode);\n        };\n        Choices.prototype._triggerChange = function (value) {\n            if (value === undefined || value === null) {\n                return;\n            }\n            this.passedElement.triggerEvent(EventType.change, {\n                value: value,\n            });\n        };\n        Choices.prototype._handleButtonAction = function (element) {\n            var _this = this;\n            var items = this._store.items;\n            if (!items.length || !this.config.removeItems || !this.config.removeItemButton) {\n                return;\n            }\n            var id = element && parseDataSetId(element.closest('[data-id]'));\n            var itemToRemove = id && items.find(function (item) { return item.id === id; });\n            if (!itemToRemove) {\n                return;\n            }\n            this._store.withTxn(function () {\n                // Remove item associated with button\n                _this._removeItem(itemToRemove);\n                _this._triggerChange(itemToRemove.value);\n                if (_this._isSelectOneElement && !_this._hasNonChoicePlaceholder) {\n                    var placeholderChoice = (_this.config.shouldSort ? _this._store.choices.reverse() : _this._store.choices).find(function (choice) { return choice.placeholder; });\n                    if (placeholderChoice) {\n                        _this._addItem(placeholderChoice);\n                        _this.unhighlightAll();\n                        if (placeholderChoice.value) {\n                            _this._triggerChange(placeholderChoice.value);\n                        }\n                    }\n                }\n            });\n        };\n        Choices.prototype._handleItemAction = function (element, hasShiftKey) {\n            var _this = this;\n            if (hasShiftKey === void 0) { hasShiftKey = false; }\n            var items = this._store.items;\n            if (!items.length || !this.config.removeItems || this._isSelectOneElement) {\n                return;\n            }\n            var id = parseDataSetId(element);\n            if (!id) {\n                return;\n            }\n            // We only want to select one item with a click\n            // so we deselect any items that aren't the target\n            // unless shift is being pressed\n            items.forEach(function (item) {\n                if (item.id === id && !item.highlighted) {\n                    _this.highlightItem(item);\n                }\n                else if (!hasShiftKey && item.highlighted) {\n                    _this.unhighlightItem(item);\n                }\n            });\n            // Focus input as without focus, a user cannot do anything with a\n            // highlighted item\n            this.input.focus();\n        };\n        Choices.prototype._handleChoiceAction = function (element) {\n            var _this = this;\n            // If we are clicking on an option\n            var id = parseDataSetId(element);\n            var choice = id && this._store.getChoiceById(id);\n            if (!choice || choice.disabled) {\n                return false;\n            }\n            var hasActiveDropdown = this.dropdown.isActive;\n            if (!choice.selected) {\n                if (!this._canAddItems()) {\n                    return true; // causes _onEnterKey to early out\n                }\n                this._store.withTxn(function () {\n                    _this._addItem(choice, true, true);\n                    _this.clearInput();\n                    _this.unhighlightAll();\n                });\n                this._triggerChange(choice.value);\n            }\n            // We want to close the dropdown if we are dealing with a single select box\n            if (hasActiveDropdown && this.config.closeDropdownOnSelect) {\n                this.hideDropdown(true);\n                this.containerOuter.element.focus();\n            }\n            return true;\n        };\n        Choices.prototype._handleBackspace = function (items) {\n            var config = this.config;\n            if (!config.removeItems || !items.length) {\n                return;\n            }\n            var lastItem = items[items.length - 1];\n            var hasHighlightedItems = items.some(function (item) { return item.highlighted; });\n            // If editing the last item is allowed and there are not other selected items,\n            // we can edit the item value. Otherwise if we can remove items, remove all selected items\n            if (config.editItems && !hasHighlightedItems && lastItem) {\n                this.input.value = lastItem.value;\n                this.input.setWidth();\n                this._removeItem(lastItem);\n                this._triggerChange(lastItem.value);\n            }\n            else {\n                if (!hasHighlightedItems) {\n                    // Highlight last item if none already highlighted\n                    this.highlightItem(lastItem, false);\n                }\n                this.removeHighlightedItems(true);\n            }\n        };\n        Choices.prototype._loadChoices = function () {\n            var _a;\n            var _this = this;\n            var config = this.config;\n            if (this._isTextElement) {\n                // Assign preset items from passed object first\n                this._presetChoices = config.items.map(function (e) { return mapInputToChoice(e, false); });\n                // Add any values passed from attribute\n                if (this.passedElement.value) {\n                    var elementItems = this.passedElement.value\n                        .split(config.delimiter)\n                        .map(function (e) { return mapInputToChoice(e, false, _this.config.allowHtmlUserInput); });\n                    this._presetChoices = this._presetChoices.concat(elementItems);\n                }\n                this._presetChoices.forEach(function (choice) {\n                    choice.selected = true;\n                });\n            }\n            else if (this._isSelectElement) {\n                // Assign preset choices from passed object\n                this._presetChoices = config.choices.map(function (e) { return mapInputToChoice(e, true); });\n                // Create array of choices from option elements\n                var choicesFromOptions = this.passedElement.optionsAsChoices();\n                if (choicesFromOptions) {\n                    (_a = this._presetChoices).push.apply(_a, choicesFromOptions);\n                }\n            }\n        };\n        Choices.prototype._handleLoadingState = function (setLoading) {\n            if (setLoading === void 0) { setLoading = true; }\n            var el = this.itemList.element;\n            if (setLoading) {\n                this.disable();\n                this.containerOuter.addLoadingState();\n                if (this._isSelectOneElement) {\n                    el.replaceChildren(this._templates.placeholder(this.config, this.config.loadingText));\n                }\n                else {\n                    this.input.placeholder = this.config.loadingText;\n                }\n            }\n            else {\n                this.enable();\n                this.containerOuter.removeLoadingState();\n                if (this._isSelectOneElement) {\n                    el.replaceChildren('');\n                    this._render();\n                }\n                else {\n                    this.input.placeholder = this._placeholderValue || '';\n                }\n            }\n        };\n        Choices.prototype._handleSearch = function (value) {\n            if (!this.input.isFocussed) {\n                return;\n            }\n            // Check that we have a value to search and the input was an alphanumeric character\n            if (value !== null && typeof value !== 'undefined' && value.length >= this.config.searchFloor) {\n                var resultCount = this.config.searchChoices ? this._searchChoices(value) : 0;\n                if (resultCount !== null) {\n                    // Trigger search event\n                    this.passedElement.triggerEvent(EventType.search, {\n                        value: value,\n                        resultCount: resultCount,\n                    });\n                }\n            }\n            else if (this._store.choices.some(function (option) { return !option.active; })) {\n                this._stopSearch();\n            }\n        };\n        Choices.prototype._canAddItems = function () {\n            var config = this.config;\n            var maxItemCount = config.maxItemCount, maxItemText = config.maxItemText;\n            if (!config.singleModeForMultiSelect && maxItemCount > 0 && maxItemCount <= this._store.items.length) {\n                this.choiceList.element.replaceChildren('');\n                this._notice = undefined;\n                this._displayNotice(typeof maxItemText === 'function' ? maxItemText(maxItemCount) : maxItemText, NoticeTypes.addChoice);\n                return false;\n            }\n            if (this._notice && this._notice.type === NoticeTypes.addChoice) {\n                this._clearNotice();\n            }\n            return true;\n        };\n        Choices.prototype._canCreateItem = function (value) {\n            var config = this.config;\n            var canAddItem = true;\n            var notice = '';\n            if (canAddItem && typeof config.addItemFilter === 'function' && !config.addItemFilter(value)) {\n                canAddItem = false;\n                notice = resolveNoticeFunction(config.customAddItemText, value, undefined);\n            }\n            if (canAddItem) {\n                var foundChoice = this._store.choices.find(function (choice) { return config.valueComparer(choice.value, value); });\n                if (foundChoice) {\n                    if (this._isSelectElement) {\n                        // for exact matches, do not prompt to add it as a custom choice\n                        this._displayNotice('', NoticeTypes.addChoice);\n                        return false;\n                    }\n                    if (!config.duplicateItemsAllowed) {\n                        canAddItem = false;\n                        notice = resolveNoticeFunction(config.uniqueItemText, value, undefined);\n                    }\n                }\n            }\n            if (canAddItem) {\n                notice = resolveNoticeFunction(config.addItemText, value, undefined);\n            }\n            if (notice) {\n                this._displayNotice(notice, NoticeTypes.addChoice);\n            }\n            return canAddItem;\n        };\n        Choices.prototype._searchChoices = function (value) {\n            var newValue = value.trim().replace(/\\s{2,}/, ' ');\n            // signal input didn't change search\n            if (!newValue.length || newValue === this._currentValue) {\n                return null;\n            }\n            var searcher = this._searcher;\n            if (searcher.isEmptyIndex()) {\n                searcher.index(this._store.searchableChoices);\n            }\n            // If new value matches the desired length and is not the same as the current value with a space\n            var results = searcher.search(newValue);\n            this._currentValue = newValue;\n            this._highlightPosition = 0;\n            this._isSearching = true;\n            var notice = this._notice;\n            var noticeType = notice && notice.type;\n            if (noticeType !== NoticeTypes.addChoice) {\n                if (!results.length) {\n                    this._displayNotice(resolveStringFunction(this.config.noResultsText), NoticeTypes.noResults);\n                }\n                else {\n                    this._clearNotice();\n                }\n            }\n            this._store.dispatch(filterChoices(results));\n            return results.length;\n        };\n        Choices.prototype._stopSearch = function () {\n            if (this._isSearching) {\n                this._currentValue = '';\n                this._isSearching = false;\n                this._clearNotice();\n                this._store.dispatch(activateChoices(true));\n                this.passedElement.triggerEvent(EventType.search, {\n                    value: '',\n                    resultCount: 0,\n                });\n            }\n        };\n        Choices.prototype._addEventListeners = function () {\n            var documentElement = this._docRoot;\n            var outerElement = this.containerOuter.element;\n            var inputElement = this.input.element;\n            var passedElement = this.passedElement.element;\n            // capture events - can cancel event processing or propagation\n            documentElement.addEventListener('touchend', this._onTouchEnd, true);\n            outerElement.addEventListener('keydown', this._onKeyDown, true);\n            outerElement.addEventListener('mousedown', this._onMouseDown, true);\n            // passive events - doesn't call `preventDefault` or `stopPropagation`\n            documentElement.addEventListener('click', this._onClick, { passive: true });\n            documentElement.addEventListener('touchmove', this._onTouchMove, {\n                passive: true,\n            });\n            this.dropdown.element.addEventListener('mouseover', this._onMouseOver, {\n                passive: true,\n            });\n            if (this._isSelectOneElement) {\n                outerElement.addEventListener('focus', this._onFocus, {\n                    passive: true,\n                });\n                outerElement.addEventListener('blur', this._onBlur, {\n                    passive: true,\n                });\n            }\n            inputElement.addEventListener('keyup', this._onKeyUp, {\n                passive: true,\n            });\n            inputElement.addEventListener('input', this._onInput, {\n                passive: true,\n            });\n            inputElement.addEventListener('focus', this._onFocus, {\n                passive: true,\n            });\n            inputElement.addEventListener('blur', this._onBlur, {\n                passive: true,\n            });\n            if (inputElement.form) {\n                inputElement.form.addEventListener('reset', this._onFormReset, {\n                    passive: true,\n                });\n            }\n            if (passedElement.hasAttribute('required')) {\n                passedElement.addEventListener('change', this._onChange, {\n                    passive: true,\n                });\n                passedElement.addEventListener('invalid', this._onInvalid, {\n                    passive: true,\n                });\n            }\n            this.input.addEventListeners();\n        };\n        Choices.prototype._removeEventListeners = function () {\n            var documentElement = this._docRoot;\n            var outerElement = this.containerOuter.element;\n            var inputElement = this.input.element;\n            var passedElement = this.passedElement.element;\n            documentElement.removeEventListener('touchend', this._onTouchEnd, true);\n            outerElement.removeEventListener('keydown', this._onKeyDown, true);\n            outerElement.removeEventListener('mousedown', this._onMouseDown, true);\n            documentElement.removeEventListener('click', this._onClick);\n            documentElement.removeEventListener('touchmove', this._onTouchMove);\n            this.dropdown.element.removeEventListener('mouseover', this._onMouseOver);\n            if (this._isSelectOneElement) {\n                outerElement.removeEventListener('focus', this._onFocus);\n                outerElement.removeEventListener('blur', this._onBlur);\n            }\n            inputElement.removeEventListener('keyup', this._onKeyUp);\n            inputElement.removeEventListener('input', this._onInput);\n            inputElement.removeEventListener('focus', this._onFocus);\n            inputElement.removeEventListener('blur', this._onBlur);\n            if (inputElement.form) {\n                inputElement.form.removeEventListener('reset', this._onFormReset);\n            }\n            if (passedElement.hasAttribute('required')) {\n                passedElement.removeEventListener('change', this._onChange);\n                passedElement.removeEventListener('invalid', this._onInvalid);\n            }\n            this.input.removeEventListeners();\n        };\n        Choices.prototype._onKeyDown = function (event) {\n            var keyCode = event.keyCode;\n            var hasActiveDropdown = this.dropdown.isActive;\n            /*\n            See:\n            https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key\n            https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values\n            https://en.wikipedia.org/wiki/UTF-16#Code_points_from_U+010000_to_U+10FFFF - UTF-16 surrogate pairs\n            https://stackoverflow.com/a/70866532 - \"Unidentified\" for mobile\n            http://www.unicode.org/versions/Unicode5.2.0/ch16.pdf#G19635 - U+FFFF is reserved (Section 16.7)\n        \n            Logic: when a key event is sent, `event.key` represents its printable value _or_ one\n            of a large list of special values indicating meta keys/functionality. In addition,\n            key events for compose functionality contain a value of `Dead` when mid-composition.\n        \n            I can't quite verify it, but non-English IMEs may also be able to generate key codes\n            for code points in the surrogate-pair range, which could potentially be seen as having\n            key.length > 1. Since `Fn` is one of the special keys, we can't distinguish by that\n            alone.\n        \n            Here, key.length === 1 means we know for sure the input was printable and not a special\n            `key` value. When the length is greater than 1, it could be either a printable surrogate\n            pair or a special `key` value. We can tell the difference by checking if the _character\n            code_ value (not code point!) is in the \"surrogate pair\" range or not.\n        \n            We don't use .codePointAt because an invalid code point would return 65535, which wouldn't\n            pass the >= 0x10000 check we would otherwise use.\n        \n            > ...The Unicode Standard sets aside 66 noncharacter code points. The last two code points\n            > of each plane are noncharacters: U+FFFE and U+FFFF on the BMP...\n            */\n            var wasPrintableChar = event.key.length === 1 ||\n                (event.key.length === 2 && event.key.charCodeAt(0) >= 0xd800) ||\n                event.key === 'Unidentified';\n            /*\n              We do not show the dropdown if focusing out with esc or navigating through input fields.\n              An activated search can still be opened with any other key.\n             */\n            if (!this._isTextElement &&\n                !hasActiveDropdown &&\n                keyCode !== KeyCodeMap.ESC_KEY &&\n                keyCode !== KeyCodeMap.TAB_KEY &&\n                keyCode !== KeyCodeMap.SHIFT_KEY) {\n                this.showDropdown();\n                if (!this.input.isFocussed && wasPrintableChar) {\n                    /*\n                      We update the input value with the pressed key as\n                      the input was not focussed at the time of key press\n                      therefore does not have the value of the key.\n                    */\n                    this.input.value += event.key;\n                    // browsers interpret a space as pagedown\n                    if (event.key === ' ') {\n                        event.preventDefault();\n                    }\n                }\n            }\n            switch (keyCode) {\n                case KeyCodeMap.A_KEY:\n                    return this._onSelectKey(event, this.itemList.element.hasChildNodes());\n                case KeyCodeMap.ENTER_KEY:\n                    return this._onEnterKey(event, hasActiveDropdown);\n                case KeyCodeMap.ESC_KEY:\n                    return this._onEscapeKey(event, hasActiveDropdown);\n                case KeyCodeMap.UP_KEY:\n                case KeyCodeMap.PAGE_UP_KEY:\n                case KeyCodeMap.DOWN_KEY:\n                case KeyCodeMap.PAGE_DOWN_KEY:\n                    return this._onDirectionKey(event, hasActiveDropdown);\n                case KeyCodeMap.DELETE_KEY:\n                case KeyCodeMap.BACK_KEY:\n                    return this._onDeleteKey(event, this._store.items, this.input.isFocussed);\n            }\n        };\n        Choices.prototype._onKeyUp = function ( /* event: KeyboardEvent */) {\n            this._canSearch = this.config.searchEnabled;\n        };\n        Choices.prototype._onInput = function ( /* event: InputEvent */) {\n            var value = this.input.value;\n            if (!value) {\n                if (this._isTextElement) {\n                    this.hideDropdown(true);\n                }\n                else {\n                    this._stopSearch();\n                }\n                return;\n            }\n            if (!this._canAddItems()) {\n                return;\n            }\n            if (this._canSearch) {\n                // do the search even if the entered text can not be added\n                this._handleSearch(value);\n            }\n            if (!this._canAddUserChoices) {\n                return;\n            }\n            // determine if a notice needs to be displayed for why a search result can't be added\n            this._canCreateItem(value);\n            if (this._isSelectElement) {\n                this._highlightPosition = 0; // reset to select the notice and/or exact match\n                this._highlightChoice();\n            }\n        };\n        Choices.prototype._onSelectKey = function (event, hasItems) {\n            // If CTRL + A or CMD + A have been pressed and there are items to select\n            if ((event.ctrlKey || event.metaKey) && hasItems) {\n                this._canSearch = false;\n                var shouldHightlightAll = this.config.removeItems && !this.input.value && this.input.element === document.activeElement;\n                if (shouldHightlightAll) {\n                    this.highlightAll();\n                }\n            }\n        };\n        Choices.prototype._onEnterKey = function (event, hasActiveDropdown) {\n            var _this = this;\n            var value = this.input.value;\n            var target = event.target;\n            event.preventDefault();\n            if (target && target.hasAttribute('data-button')) {\n                this._handleButtonAction(target);\n                return;\n            }\n            if (!hasActiveDropdown) {\n                if (this._isSelectElement || this._notice) {\n                    this.showDropdown();\n                }\n                return;\n            }\n            var highlightedChoice = this.dropdown.element.querySelector(getClassNamesSelector(this.config.classNames.highlightedState));\n            if (highlightedChoice && this._handleChoiceAction(highlightedChoice)) {\n                return;\n            }\n            if (!target || !value) {\n                this.hideDropdown(true);\n                return;\n            }\n            if (!this._canAddItems()) {\n                return;\n            }\n            var addedItem = false;\n            this._store.withTxn(function () {\n                addedItem = _this._findAndSelectChoiceByValue(value, true);\n                if (!addedItem) {\n                    if (!_this._canAddUserChoices) {\n                        return;\n                    }\n                    if (!_this._canCreateItem(value)) {\n                        return;\n                    }\n                    _this._addChoice(mapInputToChoice(value, false, _this.config.allowHtmlUserInput), true, true);\n                    addedItem = true;\n                }\n                _this.clearInput();\n                _this.unhighlightAll();\n            });\n            if (!addedItem) {\n                return;\n            }\n            this._triggerChange(value);\n            if (this.config.closeDropdownOnSelect) {\n                this.hideDropdown(true);\n            }\n        };\n        Choices.prototype._onEscapeKey = function (event, hasActiveDropdown) {\n            if (hasActiveDropdown) {\n                event.stopPropagation();\n                this.hideDropdown(true);\n                this._stopSearch();\n                this.containerOuter.element.focus();\n            }\n        };\n        Choices.prototype._onDirectionKey = function (event, hasActiveDropdown) {\n            var keyCode = event.keyCode;\n            // If up or down key is pressed, traverse through options\n            if (hasActiveDropdown || this._isSelectOneElement) {\n                this.showDropdown();\n                this._canSearch = false;\n                var directionInt = keyCode === KeyCodeMap.DOWN_KEY || keyCode === KeyCodeMap.PAGE_DOWN_KEY ? 1 : -1;\n                var skipKey = event.metaKey || keyCode === KeyCodeMap.PAGE_DOWN_KEY || keyCode === KeyCodeMap.PAGE_UP_KEY;\n                var nextEl = void 0;\n                if (skipKey) {\n                    if (directionInt > 0) {\n                        nextEl = this.dropdown.element.querySelector(\"\".concat(selectableChoiceIdentifier, \":last-of-type\"));\n                    }\n                    else {\n                        nextEl = this.dropdown.element.querySelector(selectableChoiceIdentifier);\n                    }\n                }\n                else {\n                    var currentEl = this.dropdown.element.querySelector(getClassNamesSelector(this.config.classNames.highlightedState));\n                    if (currentEl) {\n                        nextEl = getAdjacentEl(currentEl, selectableChoiceIdentifier, directionInt);\n                    }\n                    else {\n                        nextEl = this.dropdown.element.querySelector(selectableChoiceIdentifier);\n                    }\n                }\n                if (nextEl) {\n                    // We prevent default to stop the cursor moving\n                    // when pressing the arrow\n                    if (!isScrolledIntoView(nextEl, this.choiceList.element, directionInt)) {\n                        this.choiceList.scrollToChildElement(nextEl, directionInt);\n                    }\n                    this._highlightChoice(nextEl);\n                }\n                // Prevent default to maintain cursor position whilst\n                // traversing dropdown options\n                event.preventDefault();\n            }\n        };\n        Choices.prototype._onDeleteKey = function (event, items, hasFocusedInput) {\n            // If backspace or delete key is pressed and the input has no value\n            if (!this._isSelectOneElement && !event.target.value && hasFocusedInput) {\n                this._handleBackspace(items);\n                event.preventDefault();\n            }\n        };\n        Choices.prototype._onTouchMove = function () {\n            if (this._wasTap) {\n                this._wasTap = false;\n            }\n        };\n        Choices.prototype._onTouchEnd = function (event) {\n            var target = (event || event.touches[0]).target;\n            var touchWasWithinContainer = this._wasTap && this.containerOuter.element.contains(target);\n            if (touchWasWithinContainer) {\n                var containerWasExactTarget = target === this.containerOuter.element || target === this.containerInner.element;\n                if (containerWasExactTarget) {\n                    if (this._isTextElement) {\n                        this.input.focus();\n                    }\n                    else if (this._isSelectMultipleElement) {\n                        this.showDropdown();\n                    }\n                }\n                // Prevents focus event firing\n                event.stopPropagation();\n            }\n            this._wasTap = true;\n        };\n        /**\n         * Handles mousedown event in capture mode for containetOuter.element\n         */\n        Choices.prototype._onMouseDown = function (event) {\n            var target = event.target;\n            if (!(target instanceof Element)) {\n                return;\n            }\n            // If we have our mouse down on the scrollbar and are on IE11...\n            if (IS_IE11 && this.choiceList.element.contains(target)) {\n                // check if click was on a scrollbar area\n                var firstChoice = this.choiceList.element.firstElementChild;\n                this._isScrollingOnIe =\n                    this._direction === 'ltr' ? event.offsetX >= firstChoice.offsetWidth : event.offsetX < firstChoice.offsetLeft;\n            }\n            if (target === this.input.element) {\n                return;\n            }\n            var item = target.closest('[data-button],[data-item],[data-choice]');\n            if (item instanceof HTMLElement) {\n                if ('button' in item.dataset) {\n                    this._handleButtonAction(item);\n                }\n                else if ('item' in item.dataset) {\n                    this._handleItemAction(item, event.shiftKey);\n                }\n                else if ('choice' in item.dataset) {\n                    this._handleChoiceAction(item);\n                }\n            }\n            event.preventDefault();\n        };\n        /**\n         * Handles mouseover event over this.dropdown\n         * @param {MouseEvent} event\n         */\n        Choices.prototype._onMouseOver = function (_a) {\n            var target = _a.target;\n            if (target instanceof HTMLElement && 'choice' in target.dataset) {\n                this._highlightChoice(target);\n            }\n        };\n        Choices.prototype._onClick = function (_a) {\n            var target = _a.target;\n            var containerOuter = this.containerOuter;\n            var clickWasWithinContainer = containerOuter.element.contains(target);\n            if (clickWasWithinContainer) {\n                if (!this.dropdown.isActive && !containerOuter.isDisabled) {\n                    if (this._isTextElement) {\n                        if (document.activeElement !== this.input.element) {\n                            this.input.focus();\n                        }\n                    }\n                    else {\n                        this.showDropdown();\n                        containerOuter.element.focus();\n                    }\n                }\n                else if (this._isSelectOneElement &&\n                    target !== this.input.element &&\n                    !this.dropdown.element.contains(target)) {\n                    this.hideDropdown();\n                }\n            }\n            else {\n                containerOuter.removeFocusState();\n                this.hideDropdown(true);\n                this.unhighlightAll();\n            }\n        };\n        Choices.prototype._onFocus = function (_a) {\n            var target = _a.target;\n            var containerOuter = this.containerOuter;\n            var focusWasWithinContainer = target && containerOuter.element.contains(target);\n            if (!focusWasWithinContainer) {\n                return;\n            }\n            var targetIsInput = target === this.input.element;\n            if (this._isTextElement) {\n                if (targetIsInput) {\n                    containerOuter.addFocusState();\n                }\n            }\n            else if (this._isSelectMultipleElement) {\n                if (targetIsInput) {\n                    this.showDropdown(true);\n                    // If element is a select box, the focused element is the container and the dropdown\n                    // isn't already open, focus and show dropdown\n                    containerOuter.addFocusState();\n                }\n            }\n            else {\n                containerOuter.addFocusState();\n                if (targetIsInput) {\n                    this.showDropdown(true);\n                }\n            }\n        };\n        Choices.prototype._onBlur = function (_a) {\n            var target = _a.target;\n            var containerOuter = this.containerOuter;\n            var blurWasWithinContainer = target && containerOuter.element.contains(target);\n            if (blurWasWithinContainer && !this._isScrollingOnIe) {\n                if (target === this.input.element) {\n                    containerOuter.removeFocusState();\n                    this.hideDropdown(true);\n                    if (this._isTextElement || this._isSelectMultipleElement) {\n                        this.unhighlightAll();\n                    }\n                }\n                else if (target === this.containerOuter.element) {\n                    // Remove the focus state when the past outerContainer was the target\n                    containerOuter.removeFocusState();\n                    // Also close the dropdown if search is disabled\n                    if (!this.config.searchEnabled) {\n                        this.hideDropdown(true);\n                    }\n                }\n            }\n            else {\n                // On IE11, clicking the scollbar blurs our input and thus\n                // closes the dropdown. To stop this, we refocus our input\n                // if we know we are on IE *and* are scrolling.\n                this._isScrollingOnIe = false;\n                this.input.element.focus();\n            }\n        };\n        Choices.prototype._onFormReset = function () {\n            var _this = this;\n            this._store.withTxn(function () {\n                _this.clearInput();\n                _this.hideDropdown();\n                _this.refresh(false, false, true);\n                if (_this._initialItems.length) {\n                    _this.setChoiceByValue(_this._initialItems);\n                }\n            });\n        };\n        Choices.prototype._onChange = function (event) {\n            if (!event.target.checkValidity()) {\n                return;\n            }\n            this.containerOuter.removeInvalidState();\n        };\n        Choices.prototype._onInvalid = function () {\n            this.containerOuter.addInvalidState();\n        };\n        /**\n         * Removes any highlighted choice options\n         */\n        Choices.prototype._removeHighlightedChoices = function () {\n            var highlightedState = this.config.classNames.highlightedState;\n            var highlightedChoices = Array.from(this.dropdown.element.querySelectorAll(getClassNamesSelector(highlightedState)));\n            // Remove any highlighted choices\n            highlightedChoices.forEach(function (choice) {\n                removeClassesFromElement(choice, highlightedState);\n                choice.setAttribute('aria-selected', 'false');\n            });\n        };\n        Choices.prototype._highlightChoice = function (el) {\n            if (el === void 0) { el = null; }\n            var choices = Array.from(this.dropdown.element.querySelectorAll(selectableChoiceIdentifier));\n            if (!choices.length) {\n                return;\n            }\n            var passedEl = el;\n            var highlightedState = this.config.classNames.highlightedState;\n            this._removeHighlightedChoices();\n            if (passedEl) {\n                this._highlightPosition = choices.indexOf(passedEl);\n            }\n            else {\n                // Highlight choice based on last known highlight location\n                if (choices.length > this._highlightPosition) {\n                    // If we have an option to highlight\n                    passedEl = choices[this._highlightPosition];\n                }\n                else {\n                    // Otherwise highlight the option before\n                    passedEl = choices[choices.length - 1];\n                }\n                if (!passedEl) {\n                    passedEl = choices[0];\n                }\n            }\n            addClassesToElement(passedEl, highlightedState);\n            passedEl.setAttribute('aria-selected', 'true');\n            this.passedElement.triggerEvent(EventType.highlightChoice, {\n                el: passedEl,\n            });\n            if (this.dropdown.isActive) {\n                // IE11 ignores aria-label and blocks virtual keyboard\n                // if aria-activedescendant is set without a dropdown\n                this.input.setActiveDescendant(passedEl.id);\n                this.containerOuter.setActiveDescendant(passedEl.id);\n            }\n        };\n        Choices.prototype._addItem = function (item, withEvents, userTriggered) {\n            if (withEvents === void 0) { withEvents = true; }\n            if (userTriggered === void 0) { userTriggered = false; }\n            if (!item.id) {\n                throw new TypeError('item.id must be set before _addItem is called for a choice/item');\n            }\n            if (this.config.singleModeForMultiSelect || this._isSelectOneElement) {\n                this.removeActiveItems(item.id);\n            }\n            this._store.dispatch(addItem(item));\n            if (withEvents) {\n                var eventChoice = getChoiceForOutput(item);\n                this.passedElement.triggerEvent(EventType.addItem, eventChoice);\n                if (userTriggered) {\n                    this.passedElement.triggerEvent(EventType.choice, eventChoice);\n                }\n            }\n        };\n        Choices.prototype._removeItem = function (item) {\n            if (!item.id) {\n                return;\n            }\n            this._store.dispatch(removeItem$1(item));\n            var notice = this._notice;\n            if (notice && notice.type === NoticeTypes.noChoices) {\n                this._clearNotice();\n            }\n            this.passedElement.triggerEvent(EventType.removeItem, getChoiceForOutput(item));\n        };\n        Choices.prototype._addChoice = function (choice, withEvents, userTriggered) {\n            if (withEvents === void 0) { withEvents = true; }\n            if (userTriggered === void 0) { userTriggered = false; }\n            if (choice.id) {\n                throw new TypeError('Can not re-add a choice which has already been added');\n            }\n            var config = this.config;\n            if (!config.duplicateItemsAllowed && this._store.choices.find(function (c) { return config.valueComparer(c.value, choice.value); })) {\n                return;\n            }\n            // Generate unique id, in-place update is required so chaining _addItem works as expected\n            this._lastAddedChoiceId++;\n            choice.id = this._lastAddedChoiceId;\n            choice.elementId = \"\".concat(this._baseId, \"-\").concat(this._idNames.itemChoice, \"-\").concat(choice.id);\n            var prependValue = config.prependValue, appendValue = config.appendValue;\n            if (prependValue) {\n                choice.value = prependValue + choice.value;\n            }\n            if (appendValue) {\n                choice.value += appendValue.toString();\n            }\n            if ((prependValue || appendValue) && choice.element) {\n                choice.element.value = choice.value;\n            }\n            this._clearNotice();\n            this._store.dispatch(addChoice(choice));\n            if (choice.selected) {\n                this._addItem(choice, withEvents, userTriggered);\n            }\n        };\n        Choices.prototype._addGroup = function (group, withEvents) {\n            var _this = this;\n            if (withEvents === void 0) { withEvents = true; }\n            if (group.id) {\n                throw new TypeError('Can not re-add a group which has already been added');\n            }\n            this._store.dispatch(addGroup(group));\n            if (!group.choices) {\n                return;\n            }\n            // add unique id for the group(s), and do not store the full list of choices in this group\n            this._lastAddedGroupId++;\n            group.id = this._lastAddedGroupId;\n            group.choices.forEach(function (item) {\n                item.group = group;\n                if (group.disabled) {\n                    item.disabled = true;\n                }\n                _this._addChoice(item, withEvents);\n            });\n        };\n        Choices.prototype._createTemplates = function () {\n            var _this = this;\n            var callbackOnCreateTemplates = this.config.callbackOnCreateTemplates;\n            var userTemplates = {};\n            if (typeof callbackOnCreateTemplates === 'function') {\n                userTemplates = callbackOnCreateTemplates.call(this, strToEl, escapeForTemplate, getClassNames);\n            }\n            var templating = {};\n            Object.keys(this._templates).forEach(function (name) {\n                if (name in userTemplates) {\n                    templating[name] = userTemplates[name].bind(_this);\n                }\n                else {\n                    templating[name] = _this._templates[name].bind(_this);\n                }\n            });\n            this._templates = templating;\n        };\n        Choices.prototype._createElements = function () {\n            var templating = this._templates;\n            var _a = this, config = _a.config, isSelectOneElement = _a._isSelectOneElement;\n            var position = config.position, classNames = config.classNames;\n            var elementType = this._elementType;\n            this.containerOuter = new Container({\n                element: templating.containerOuter(config, this._direction, this._isSelectElement, isSelectOneElement, config.searchEnabled, elementType, config.labelId),\n                classNames: classNames,\n                type: elementType,\n                position: position,\n            });\n            this.containerInner = new Container({\n                element: templating.containerInner(config),\n                classNames: classNames,\n                type: elementType,\n                position: position,\n            });\n            this.input = new Input({\n                element: templating.input(config, this._placeholderValue),\n                classNames: classNames,\n                type: elementType,\n                preventPaste: !config.paste,\n            });\n            this.choiceList = new List({\n                element: templating.choiceList(config, isSelectOneElement),\n            });\n            this.itemList = new List({\n                element: templating.itemList(config, isSelectOneElement),\n            });\n            this.dropdown = new Dropdown({\n                element: templating.dropdown(config),\n                classNames: classNames,\n                type: elementType,\n            });\n        };\n        Choices.prototype._createStructure = function () {\n            var _a = this, containerInner = _a.containerInner, containerOuter = _a.containerOuter, passedElement = _a.passedElement;\n            var dropdownElement = this.dropdown.element;\n            // Hide original element\n            passedElement.conceal();\n            // Wrap input in container preserving DOM ordering\n            containerInner.wrap(passedElement.element);\n            // Wrapper inner container with outer container\n            containerOuter.wrap(containerInner.element);\n            containerOuter.element.appendChild(containerInner.element);\n            containerOuter.element.appendChild(dropdownElement);\n            containerInner.element.appendChild(this.itemList.element);\n            dropdownElement.appendChild(this.choiceList.element);\n            if (this._isSelectOneElement) {\n                this.input.placeholder = this.config.searchPlaceholderValue || '';\n                if (this.config.searchEnabled) {\n                    dropdownElement.insertBefore(this.input.element, dropdownElement.firstChild);\n                }\n            }\n            else {\n                if (!this._isSelectMultipleElement || this.config.searchEnabled) {\n                    containerInner.element.appendChild(this.input.element);\n                }\n                if (this._placeholderValue) {\n                    this.input.placeholder = this._placeholderValue;\n                }\n                this.input.setWidth();\n            }\n            this._highlightPosition = 0;\n            this._isSearching = false;\n        };\n        Choices.prototype._initStore = function () {\n            var _this = this;\n            this._store.subscribe(this._render).withTxn(function () {\n                _this._addPredefinedChoices(_this._presetChoices, _this._isSelectOneElement && !_this._hasNonChoicePlaceholder, false);\n            });\n            if (!this._store.choices.length || (this._isSelectOneElement && this._hasNonChoicePlaceholder)) {\n                this._render();\n            }\n        };\n        Choices.prototype._addPredefinedChoices = function (choices, selectFirstOption, withEvents) {\n            var _this = this;\n            if (selectFirstOption === void 0) { selectFirstOption = false; }\n            if (withEvents === void 0) { withEvents = true; }\n            if (selectFirstOption) {\n                /**\n                 * If there is a selected choice already or the choice is not the first in\n                 * the array, add each choice normally.\n                 *\n                 * Otherwise we pre-select the first enabled choice in the array (\"select-one\" only)\n                 */\n                var noSelectedChoices = choices.findIndex(function (choice) { return choice.selected; }) === -1;\n                if (noSelectedChoices) {\n                    choices.some(function (choice) {\n                        if (choice.disabled || 'choices' in choice) {\n                            return false;\n                        }\n                        choice.selected = true;\n                        return true;\n                    });\n                }\n            }\n            choices.forEach(function (item) {\n                if ('choices' in item) {\n                    if (_this._isSelectElement) {\n                        _this._addGroup(item, withEvents);\n                    }\n                }\n                else {\n                    _this._addChoice(item, withEvents);\n                }\n            });\n        };\n        Choices.prototype._findAndSelectChoiceByValue = function (value, userTriggered) {\n            var _this = this;\n            if (userTriggered === void 0) { userTriggered = false; }\n            // Check 'value' property exists and the choice isn't already selected\n            var foundChoice = this._store.choices.find(function (choice) { return _this.config.valueComparer(choice.value, value); });\n            if (foundChoice && !foundChoice.disabled && !foundChoice.selected) {\n                this._addItem(foundChoice, true, userTriggered);\n                return true;\n            }\n            return false;\n        };\n        Choices.prototype._generatePlaceholderValue = function () {\n            var config = this.config;\n            if (!config.placeholder) {\n                return null;\n            }\n            if (this._hasNonChoicePlaceholder) {\n                return config.placeholderValue;\n            }\n            if (this._isSelectElement) {\n                var placeholderOption = this.passedElement.placeholderOption;\n                return placeholderOption ? placeholderOption.text : null;\n            }\n            return null;\n        };\n        Choices.prototype._warnChoicesInitFailed = function (caller) {\n            if (this.config.silent) {\n                return;\n            }\n            if (!this.initialised) {\n                throw new TypeError(\"\".concat(caller, \" called on a non-initialised instance of Choices\"));\n            }\n            else if (!this.initialisedOK) {\n                throw new TypeError(\"\".concat(caller, \" called for an element which has multiple instances of Choices initialised on it\"));\n            }\n        };\n        Choices.version = '11.2.1';\n        return Choices;\n    }());\n\n    return Choices;\n\n}));\n"
  },
  {
    "path": "public/assets/scripts/choices.search-basic.mjs",
    "content": "/*! choices.js v11.2.1 | © 2026 Josh Johnson | https://github.com/Choices-js/Choices#readme */\n\n/******************************************************************************\nCopyright (c) Microsoft Corporation.\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\nPERFORMANCE OF THIS SOFTWARE.\n***************************************************************************** */\n/* global Reflect, Promise, SuppressedError, Symbol */\n\nvar extendStatics = function (d, b) {\n  extendStatics = Object.setPrototypeOf || {\n    __proto__: []\n  } instanceof Array && function (d, b) {\n    d.__proto__ = b;\n  } || function (d, b) {\n    for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p];\n  };\n  return extendStatics(d, b);\n};\nfunction __extends(d, b) {\n  if (typeof b !== \"function\" && b !== null) throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\n  extendStatics(d, b);\n  function __() {\n    this.constructor = d;\n  }\n  d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\n}\nvar __assign = function () {\n  __assign = Object.assign || function __assign(t) {\n    for (var s, i = 1, n = arguments.length; i < n; i++) {\n      s = arguments[i];\n      for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\n    }\n    return t;\n  };\n  return __assign.apply(this, arguments);\n};\nfunction __spreadArray(to, from, pack) {\n  if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\n    if (ar || !(i in from)) {\n      if (!ar) ar = Array.prototype.slice.call(from, 0, i);\n      ar[i] = from[i];\n    }\n  }\n  return to.concat(ar || Array.prototype.slice.call(from));\n}\ntypeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\n  var e = new Error(message);\n  return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\n};\n\nvar ActionType = {\n    ADD_CHOICE: 'ADD_CHOICE',\n    REMOVE_CHOICE: 'REMOVE_CHOICE',\n    FILTER_CHOICES: 'FILTER_CHOICES',\n    ACTIVATE_CHOICES: 'ACTIVATE_CHOICES',\n    CLEAR_CHOICES: 'CLEAR_CHOICES',\n    ADD_GROUP: 'ADD_GROUP',\n    ADD_ITEM: 'ADD_ITEM',\n    REMOVE_ITEM: 'REMOVE_ITEM',\n    HIGHLIGHT_ITEM: 'HIGHLIGHT_ITEM',\n};\n\nvar EventType = {\n    showDropdown: 'showDropdown',\n    hideDropdown: 'hideDropdown',\n    change: 'change',\n    choice: 'choice',\n    search: 'search',\n    addItem: 'addItem',\n    removeItem: 'removeItem',\n    highlightItem: 'highlightItem',\n    highlightChoice: 'highlightChoice',\n    unhighlightItem: 'unhighlightItem',\n};\n\nvar KeyCodeMap = {\n    TAB_KEY: 9,\n    SHIFT_KEY: 16,\n    BACK_KEY: 46,\n    DELETE_KEY: 8,\n    ENTER_KEY: 13,\n    A_KEY: 65,\n    ESC_KEY: 27,\n    UP_KEY: 38,\n    DOWN_KEY: 40,\n    PAGE_UP_KEY: 33,\n    PAGE_DOWN_KEY: 34,\n};\n\nvar ObjectsInConfig = ['fuseOptions', 'classNames'];\n\nvar PassedElementTypes = {\n    Text: 'text',\n    SelectOne: 'select-one',\n    SelectMultiple: 'select-multiple',\n};\n\nvar addChoice = function (choice) { return ({\n    type: ActionType.ADD_CHOICE,\n    choice: choice,\n}); };\nvar removeChoice = function (choice) { return ({\n    type: ActionType.REMOVE_CHOICE,\n    choice: choice,\n}); };\nvar filterChoices = function (results) { return ({\n    type: ActionType.FILTER_CHOICES,\n    results: results,\n}); };\nvar activateChoices = function (active) {\n    return ({\n        type: ActionType.ACTIVATE_CHOICES,\n        active: active,\n    });\n};\n\nvar addGroup = function (group) { return ({\n    type: ActionType.ADD_GROUP,\n    group: group,\n}); };\n\nvar addItem = function (item) { return ({\n    type: ActionType.ADD_ITEM,\n    item: item,\n}); };\nvar removeItem$1 = function (item) { return ({\n    type: ActionType.REMOVE_ITEM,\n    item: item,\n}); };\nvar highlightItem = function (item, highlighted) { return ({\n    type: ActionType.HIGHLIGHT_ITEM,\n    item: item,\n    highlighted: highlighted,\n}); };\n\nvar getRandomNumber = function (min, max) { return Math.floor(Math.random() * (max - min) + min); };\nvar generateChars = function (length) {\n    return Array.from({ length: length }, function () { return getRandomNumber(0, 36).toString(36); }).join('');\n};\nvar generateId = function (element, prefix) {\n    var id = element.id || (element.name && \"\".concat(element.name, \"-\").concat(generateChars(2))) || generateChars(4);\n    id = id.replace(/(:|\\.|\\[|\\]|,)/g, '');\n    id = \"\".concat(prefix, \"-\").concat(id);\n    return id;\n};\nvar getAdjacentEl = function (startEl, selector, direction) {\n    if (direction === void 0) { direction = 1; }\n    var prop = \"\".concat(direction > 0 ? 'next' : 'previous', \"ElementSibling\");\n    var sibling = startEl[prop];\n    while (sibling) {\n        if (sibling.matches(selector)) {\n            return sibling;\n        }\n        sibling = sibling[prop];\n    }\n    return null;\n};\nvar isScrolledIntoView = function (element, parent, direction) {\n    if (direction === void 0) { direction = 1; }\n    var isVisible;\n    if (direction > 0) {\n        // In view from bottom\n        isVisible = parent.scrollTop + parent.offsetHeight >= element.offsetTop + element.offsetHeight;\n    }\n    else {\n        // In view from top\n        isVisible = element.offsetTop >= parent.scrollTop;\n    }\n    return isVisible;\n};\nvar sanitise = function (value) {\n    if (typeof value !== 'string') {\n        if (value === null || value === undefined) {\n            return '';\n        }\n        if (typeof value === 'object') {\n            if ('raw' in value) {\n                return sanitise(value.raw);\n            }\n            if ('trusted' in value) {\n                return value.trusted;\n            }\n        }\n        return value;\n    }\n    return value\n        .replace(/&/g, '&amp;')\n        .replace(/>/g, '&gt;')\n        .replace(/</g, '&lt;')\n        .replace(/'/g, '&#039;')\n        .replace(/\"/g, '&quot;');\n};\nvar strToEl = (function () {\n    var tmpEl = document.createElement('div');\n    return function (str) {\n        tmpEl.innerHTML = str.trim();\n        var firstChild = tmpEl.children[0];\n        while (tmpEl.firstChild) {\n            tmpEl.removeChild(tmpEl.firstChild);\n        }\n        return firstChild;\n    };\n})();\nvar resolveStringFunction = function (fn) {\n    return typeof fn === 'function' ? fn() : fn;\n};\nvar unwrapStringForRaw = function (s) {\n    if (typeof s === 'string') {\n        return s;\n    }\n    if (typeof s === 'object') {\n        if ('trusted' in s) {\n            return s.trusted;\n        }\n        if ('raw' in s) {\n            return s.raw;\n        }\n    }\n    return '';\n};\nvar unwrapStringForEscaped = function (s) {\n    if (typeof s === 'string') {\n        return s;\n    }\n    if (typeof s === 'object') {\n        if ('escaped' in s) {\n            return s.escaped;\n        }\n        if ('trusted' in s) {\n            return s.trusted;\n        }\n    }\n    return '';\n};\nvar getChoiceForOutput = function (choice, keyCode) {\n    return {\n        id: choice.id,\n        highlighted: choice.highlighted,\n        labelClass: choice.labelClass,\n        labelDescription: unwrapStringForRaw(choice.labelDescription),\n        customProperties: choice.customProperties,\n        disabled: choice.disabled,\n        active: choice.active,\n        label: choice.label,\n        placeholder: choice.placeholder,\n        value: choice.value,\n        groupValue: choice.group ? choice.group.label : undefined,\n        element: choice.element,\n        keyCode: keyCode,\n    };\n};\nvar resolveNoticeFunction = function (fn, value, item) {\n    return typeof fn === 'function' ? fn(sanitise(value), unwrapStringForRaw(value), item) : fn;\n};\nvar escapeForTemplate = function (allowHTML, s) {\n    return allowHTML ? unwrapStringForEscaped(s) : sanitise(s);\n};\nvar setElementHtml = function (el, allowHtml, html) {\n    el.innerHTML = escapeForTemplate(allowHtml, html);\n};\nvar sortByAlpha = function (_a, _b) {\n    var value = _a.value, _c = _a.label, label = _c === void 0 ? value : _c;\n    var value2 = _b.value, _d = _b.label, label2 = _d === void 0 ? value2 : _d;\n    return unwrapStringForRaw(label).localeCompare(unwrapStringForRaw(label2), [], {\n        sensitivity: 'base',\n        ignorePunctuation: true,\n        numeric: true,\n    });\n};\nvar sortByRank = function (a, b) {\n    return a.rank - b.rank;\n};\nvar dispatchEvent = function (element, type, customArgs) {\n    if (customArgs === void 0) { customArgs = null; }\n    var event = new CustomEvent(type, {\n        detail: customArgs,\n        bubbles: true,\n        cancelable: true,\n    });\n    return element.dispatchEvent(event);\n};\n/**\n * Returns an array of keys present on the first but missing on the second object\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nvar diff = function (a, b) {\n    var aKeys = Object.keys(a).sort();\n    var bKeys = Object.keys(b).sort();\n    return aKeys.filter(function (i) { return bKeys.indexOf(i) < 0; });\n};\nvar getClassNames = function (ClassNames) {\n    return Array.isArray(ClassNames) ? ClassNames : [ClassNames];\n};\nvar getClassNamesSelector = function (option) {\n    if (option && Array.isArray(option)) {\n        return option\n            .map(function (item) {\n            return \".\".concat(item);\n        })\n            .join('');\n    }\n    return \".\".concat(option);\n};\nvar addClassesToElement = function (element, className) {\n    var _a;\n    (_a = element.classList).add.apply(_a, getClassNames(className));\n};\nvar removeClassesFromElement = function (element, className) {\n    var _a;\n    (_a = element.classList).remove.apply(_a, getClassNames(className));\n};\nvar parseCustomProperties = function (customProperties) {\n    if (typeof customProperties !== 'undefined') {\n        try {\n            return JSON.parse(customProperties);\n        }\n        catch (e) {\n            return customProperties;\n        }\n    }\n    return {};\n};\nvar updateClassList = function (item, add, remove) {\n    var itemEl = item.itemEl;\n    if (itemEl) {\n        removeClassesFromElement(itemEl, remove);\n        addClassesToElement(itemEl, add);\n    }\n};\n\nvar Dropdown = /** @class */ (function () {\n    function Dropdown(_a) {\n        var element = _a.element, type = _a.type, classNames = _a.classNames;\n        this.element = element;\n        this.classNames = classNames;\n        this.type = type;\n        this.isActive = false;\n    }\n    /**\n     * Show dropdown to user by adding active state class\n     */\n    Dropdown.prototype.show = function () {\n        addClassesToElement(this.element, this.classNames.activeState);\n        this.element.setAttribute('aria-expanded', 'true');\n        this.isActive = true;\n        return this;\n    };\n    /**\n     * Hide dropdown from user\n     */\n    Dropdown.prototype.hide = function () {\n        removeClassesFromElement(this.element, this.classNames.activeState);\n        this.element.setAttribute('aria-expanded', 'false');\n        this.isActive = false;\n        return this;\n    };\n    return Dropdown;\n}());\n\nvar Container = /** @class */ (function () {\n    function Container(_a) {\n        var element = _a.element, type = _a.type, classNames = _a.classNames, position = _a.position;\n        this.element = element;\n        this.classNames = classNames;\n        this.type = type;\n        this.position = position;\n        this.isOpen = false;\n        this.isFlipped = false;\n        this.isDisabled = false;\n        this.isLoading = false;\n    }\n    /**\n     * Determine whether container should be flipped based on passed\n     * dropdown position\n     */\n    Container.prototype.shouldFlip = function (dropdownPos, dropdownHeight) {\n        // If flip is enabled and the dropdown bottom position is\n        // greater than the window height flip the dropdown.\n        var shouldFlip = false;\n        if (this.position === 'auto') {\n            shouldFlip =\n                this.element.getBoundingClientRect().top - dropdownHeight >= 0 &&\n                    !window.matchMedia(\"(min-height: \".concat(dropdownPos + 1, \"px)\")).matches;\n        }\n        else if (this.position === 'top') {\n            shouldFlip = true;\n        }\n        return shouldFlip;\n    };\n    Container.prototype.setActiveDescendant = function (activeDescendantID) {\n        this.element.setAttribute('aria-activedescendant', activeDescendantID);\n    };\n    Container.prototype.removeActiveDescendant = function () {\n        this.element.removeAttribute('aria-activedescendant');\n    };\n    Container.prototype.open = function (dropdownPos, dropdownHeight) {\n        addClassesToElement(this.element, this.classNames.openState);\n        this.element.setAttribute('aria-expanded', 'true');\n        this.isOpen = true;\n        if (this.shouldFlip(dropdownPos, dropdownHeight)) {\n            addClassesToElement(this.element, this.classNames.flippedState);\n            this.isFlipped = true;\n        }\n    };\n    Container.prototype.close = function () {\n        removeClassesFromElement(this.element, this.classNames.openState);\n        this.element.setAttribute('aria-expanded', 'false');\n        this.removeActiveDescendant();\n        this.isOpen = false;\n        // A dropdown flips if it does not have space within the page\n        if (this.isFlipped) {\n            removeClassesFromElement(this.element, this.classNames.flippedState);\n            this.isFlipped = false;\n        }\n    };\n    Container.prototype.addFocusState = function () {\n        addClassesToElement(this.element, this.classNames.focusState);\n    };\n    Container.prototype.removeFocusState = function () {\n        removeClassesFromElement(this.element, this.classNames.focusState);\n    };\n    Container.prototype.addInvalidState = function () {\n        addClassesToElement(this.element, this.classNames.invalidState);\n    };\n    Container.prototype.removeInvalidState = function () {\n        removeClassesFromElement(this.element, this.classNames.invalidState);\n    };\n    Container.prototype.enable = function () {\n        removeClassesFromElement(this.element, this.classNames.disabledState);\n        this.element.removeAttribute('aria-disabled');\n        if (this.type === PassedElementTypes.SelectOne) {\n            this.element.setAttribute('tabindex', '0');\n        }\n        this.isDisabled = false;\n    };\n    Container.prototype.disable = function () {\n        addClassesToElement(this.element, this.classNames.disabledState);\n        this.element.setAttribute('aria-disabled', 'true');\n        if (this.type === PassedElementTypes.SelectOne) {\n            this.element.setAttribute('tabindex', '-1');\n        }\n        this.isDisabled = true;\n    };\n    Container.prototype.wrap = function (element) {\n        var el = this.element;\n        var parentNode = element.parentNode;\n        if (parentNode) {\n            if (element.nextSibling) {\n                parentNode.insertBefore(el, element.nextSibling);\n            }\n            else {\n                parentNode.appendChild(el);\n            }\n        }\n        el.appendChild(element);\n    };\n    Container.prototype.unwrap = function (element) {\n        var el = this.element;\n        var parentNode = el.parentNode;\n        if (parentNode) {\n            // Move passed element outside this element\n            parentNode.insertBefore(element, el);\n            // Remove this element\n            parentNode.removeChild(el);\n        }\n    };\n    Container.prototype.addLoadingState = function () {\n        addClassesToElement(this.element, this.classNames.loadingState);\n        this.element.setAttribute('aria-busy', 'true');\n        this.isLoading = true;\n    };\n    Container.prototype.removeLoadingState = function () {\n        removeClassesFromElement(this.element, this.classNames.loadingState);\n        this.element.removeAttribute('aria-busy');\n        this.isLoading = false;\n    };\n    return Container;\n}());\n\nvar Input = /** @class */ (function () {\n    function Input(_a) {\n        var element = _a.element, type = _a.type, classNames = _a.classNames, preventPaste = _a.preventPaste;\n        this.element = element;\n        this.type = type;\n        this.classNames = classNames;\n        this.preventPaste = preventPaste;\n        this.isFocussed = this.element.isEqualNode(document.activeElement);\n        this.isDisabled = element.disabled;\n        this._onPaste = this._onPaste.bind(this);\n        this._onInput = this._onInput.bind(this);\n        this._onFocus = this._onFocus.bind(this);\n        this._onBlur = this._onBlur.bind(this);\n    }\n    Object.defineProperty(Input.prototype, \"placeholder\", {\n        set: function (placeholder) {\n            this.element.placeholder = placeholder;\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(Input.prototype, \"value\", {\n        get: function () {\n            return this.element.value;\n        },\n        set: function (value) {\n            this.element.value = value;\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Input.prototype.addEventListeners = function () {\n        var el = this.element;\n        el.addEventListener('paste', this._onPaste);\n        el.addEventListener('input', this._onInput, {\n            passive: true,\n        });\n        el.addEventListener('focus', this._onFocus, {\n            passive: true,\n        });\n        el.addEventListener('blur', this._onBlur, {\n            passive: true,\n        });\n    };\n    Input.prototype.removeEventListeners = function () {\n        var el = this.element;\n        el.removeEventListener('input', this._onInput);\n        el.removeEventListener('paste', this._onPaste);\n        el.removeEventListener('focus', this._onFocus);\n        el.removeEventListener('blur', this._onBlur);\n    };\n    Input.prototype.enable = function () {\n        var el = this.element;\n        el.removeAttribute('disabled');\n        this.isDisabled = false;\n    };\n    Input.prototype.disable = function () {\n        var el = this.element;\n        el.setAttribute('disabled', '');\n        this.isDisabled = true;\n    };\n    Input.prototype.focus = function () {\n        if (!this.isFocussed) {\n            this.element.focus();\n        }\n    };\n    Input.prototype.blur = function () {\n        if (this.isFocussed) {\n            this.element.blur();\n        }\n    };\n    Input.prototype.clear = function (setWidth) {\n        if (setWidth === void 0) { setWidth = true; }\n        this.element.value = '';\n        if (setWidth) {\n            this.setWidth();\n        }\n        return this;\n    };\n    /**\n     * Set the correct input width based on placeholder\n     * value or input value\n     */\n    Input.prototype.setWidth = function () {\n        // Resize input to contents or placeholder\n        var element = this.element;\n        element.style.minWidth = \"\".concat(element.placeholder.length + 1, \"ch\");\n        element.style.width = \"\".concat(element.value.length + 1, \"ch\");\n    };\n    Input.prototype.setActiveDescendant = function (activeDescendantID) {\n        this.element.setAttribute('aria-activedescendant', activeDescendantID);\n    };\n    Input.prototype.removeActiveDescendant = function () {\n        this.element.removeAttribute('aria-activedescendant');\n    };\n    Input.prototype._onInput = function () {\n        if (this.type !== PassedElementTypes.SelectOne) {\n            this.setWidth();\n        }\n    };\n    Input.prototype._onPaste = function (event) {\n        if (this.preventPaste) {\n            event.preventDefault();\n        }\n    };\n    Input.prototype._onFocus = function () {\n        this.isFocussed = true;\n    };\n    Input.prototype._onBlur = function () {\n        this.isFocussed = false;\n    };\n    return Input;\n}());\n\nvar SCROLLING_SPEED = 4;\n\nvar List = /** @class */ (function () {\n    function List(_a) {\n        var element = _a.element;\n        this.element = element;\n        this.scrollPos = this.element.scrollTop;\n        this.height = this.element.offsetHeight;\n    }\n    List.prototype.prepend = function (node) {\n        var child = this.element.firstElementChild;\n        if (child) {\n            this.element.insertBefore(node, child);\n        }\n        else {\n            this.element.append(node);\n        }\n    };\n    List.prototype.scrollToTop = function () {\n        this.element.scrollTop = 0;\n    };\n    List.prototype.scrollToChildElement = function (element, direction) {\n        var _this = this;\n        if (!element) {\n            return;\n        }\n        var listHeight = this.element.offsetHeight;\n        // Scroll position of dropdown\n        var listScrollPosition = this.element.scrollTop + listHeight;\n        var elementHeight = element.offsetHeight;\n        // Distance from bottom of element to top of parent\n        var elementPos = element.offsetTop + elementHeight;\n        // Difference between the element and scroll position\n        var destination = direction > 0 ? this.element.scrollTop + elementPos - listScrollPosition : element.offsetTop;\n        requestAnimationFrame(function () {\n            _this._animateScroll(destination, direction);\n        });\n    };\n    List.prototype._scrollDown = function (scrollPos, strength, destination) {\n        var easing = (destination - scrollPos) / strength;\n        var distance = easing > 1 ? easing : 1;\n        this.element.scrollTop = scrollPos + distance;\n    };\n    List.prototype._scrollUp = function (scrollPos, strength, destination) {\n        var easing = (scrollPos - destination) / strength;\n        var distance = easing > 1 ? easing : 1;\n        this.element.scrollTop = scrollPos - distance;\n    };\n    List.prototype._animateScroll = function (destination, direction) {\n        var _this = this;\n        var strength = SCROLLING_SPEED;\n        var choiceListScrollTop = this.element.scrollTop;\n        var continueAnimation = false;\n        if (direction > 0) {\n            this._scrollDown(choiceListScrollTop, strength, destination);\n            if (choiceListScrollTop < destination) {\n                continueAnimation = true;\n            }\n        }\n        else {\n            this._scrollUp(choiceListScrollTop, strength, destination);\n            if (choiceListScrollTop > destination) {\n                continueAnimation = true;\n            }\n        }\n        if (continueAnimation) {\n            requestAnimationFrame(function () {\n                _this._animateScroll(destination, direction);\n            });\n        }\n    };\n    return List;\n}());\n\nvar WrappedElement = /** @class */ (function () {\n    function WrappedElement(_a) {\n        var element = _a.element, classNames = _a.classNames;\n        this.element = element;\n        this.classNames = classNames;\n        this.isDisabled = false;\n    }\n    Object.defineProperty(WrappedElement.prototype, \"isActive\", {\n        get: function () {\n            return this.element.dataset.choice === 'active';\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(WrappedElement.prototype, \"dir\", {\n        get: function () {\n            return this.element.dir;\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(WrappedElement.prototype, \"value\", {\n        get: function () {\n            return this.element.value;\n        },\n        set: function (value) {\n            this.element.setAttribute('value', value);\n            this.element.value = value;\n        },\n        enumerable: false,\n        configurable: true\n    });\n    WrappedElement.prototype.conceal = function () {\n        var el = this.element;\n        // Hide passed input\n        addClassesToElement(el, this.classNames.input);\n        el.hidden = true;\n        // Remove element from tab index\n        el.tabIndex = -1;\n        // Backup original styles if any\n        var origStyle = el.getAttribute('style');\n        if (origStyle) {\n            el.setAttribute('data-choice-orig-style', origStyle);\n        }\n        el.setAttribute('data-choice', 'active');\n    };\n    WrappedElement.prototype.reveal = function () {\n        var el = this.element;\n        // Reinstate passed element\n        removeClassesFromElement(el, this.classNames.input);\n        el.hidden = false;\n        el.removeAttribute('tabindex');\n        // Recover original styles if any\n        var origStyle = el.getAttribute('data-choice-orig-style');\n        if (origStyle) {\n            el.removeAttribute('data-choice-orig-style');\n            el.setAttribute('style', origStyle);\n        }\n        else {\n            el.removeAttribute('style');\n        }\n        el.removeAttribute('data-choice');\n    };\n    WrappedElement.prototype.enable = function () {\n        this.element.removeAttribute('disabled');\n        this.element.disabled = false;\n        this.isDisabled = false;\n    };\n    WrappedElement.prototype.disable = function () {\n        this.element.setAttribute('disabled', '');\n        this.element.disabled = true;\n        this.isDisabled = true;\n    };\n    WrappedElement.prototype.triggerEvent = function (eventType, data) {\n        dispatchEvent(this.element, eventType, data || {});\n    };\n    return WrappedElement;\n}());\n\nvar WrappedInput = /** @class */ (function (_super) {\n    __extends(WrappedInput, _super);\n    function WrappedInput() {\n        return _super !== null && _super.apply(this, arguments) || this;\n    }\n    return WrappedInput;\n}(WrappedElement));\n\nvar coerceBool = function (arg, defaultValue) {\n    if (defaultValue === void 0) { defaultValue = true; }\n    return typeof arg === 'undefined' ? defaultValue : !!arg;\n};\nvar stringToHtmlClass = function (input) {\n    if (typeof input === 'string') {\n        // eslint-disable-next-line no-param-reassign\n        input = input.split(' ').filter(function (s) { return s.length; });\n    }\n    if (Array.isArray(input) && input.length) {\n        return input;\n    }\n    return undefined;\n};\nvar mapInputToChoice = function (value, allowGroup, allowRawString) {\n    if (allowRawString === void 0) { allowRawString = true; }\n    if (typeof value === 'string') {\n        var sanitisedValue = sanitise(value);\n        var userValue = allowRawString || sanitisedValue === value ? value : { escaped: sanitisedValue, raw: value };\n        var result_1 = mapInputToChoice({\n            value: value,\n            label: userValue,\n            selected: true,\n        }, false);\n        return result_1;\n    }\n    var groupOrChoice = value;\n    if ('choices' in groupOrChoice) {\n        if (!allowGroup) {\n            // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/optgroup\n            throw new TypeError(\"optGroup is not allowed\");\n        }\n        var group = groupOrChoice;\n        var choices = group.choices.map(function (e) { return mapInputToChoice(e, false); });\n        var result_2 = {\n            id: 0, // actual ID will be assigned during _addGroup\n            label: unwrapStringForRaw(group.label) || group.value,\n            active: !!choices.length,\n            disabled: !!group.disabled,\n            choices: choices,\n        };\n        return result_2;\n    }\n    var choice = groupOrChoice;\n    var result = {\n        id: 0, // actual ID will be assigned during _addChoice\n        group: null, // actual group will be assigned during _addGroup but before _addChoice\n        score: 0, // used in search\n        rank: 0, // used in search, stable sort order\n        value: choice.value,\n        label: choice.label || choice.value,\n        active: coerceBool(choice.active),\n        selected: coerceBool(choice.selected, false),\n        disabled: coerceBool(choice.disabled, false),\n        placeholder: coerceBool(choice.placeholder, false),\n        highlighted: false,\n        labelClass: stringToHtmlClass(choice.labelClass),\n        labelDescription: choice.labelDescription,\n        customProperties: choice.customProperties,\n    };\n    return result;\n};\n\nvar isHtmlInputElement = function (e) { return e.tagName === 'INPUT'; };\nvar isHtmlSelectElement = function (e) { return e.tagName === 'SELECT'; };\nvar isHtmlOption = function (e) { return e.tagName === 'OPTION'; };\nvar isHtmlOptgroup = function (e) { return e.tagName === 'OPTGROUP'; };\n\nvar WrappedSelect = /** @class */ (function (_super) {\n    __extends(WrappedSelect, _super);\n    function WrappedSelect(_a) {\n        var element = _a.element, classNames = _a.classNames, template = _a.template, extractPlaceholder = _a.extractPlaceholder;\n        var _this = _super.call(this, { element: element, classNames: classNames }) || this;\n        _this.template = template;\n        _this.extractPlaceholder = extractPlaceholder;\n        return _this;\n    }\n    Object.defineProperty(WrappedSelect.prototype, \"placeholderOption\", {\n        get: function () {\n            return (this.element.querySelector('option[value=\"\"]') ||\n                // Backward compatibility layer for the non-standard placeholder attribute supported in older versions.\n                this.element.querySelector('option[placeholder]'));\n        },\n        enumerable: false,\n        configurable: true\n    });\n    WrappedSelect.prototype.addOptions = function (choices) {\n        var _this = this;\n        var fragment = document.createDocumentFragment();\n        choices.forEach(function (obj) {\n            var choice = obj;\n            if (choice.element) {\n                return;\n            }\n            var option = _this.template(choice);\n            fragment.appendChild(option);\n            choice.element = option;\n        });\n        this.element.appendChild(fragment);\n    };\n    WrappedSelect.prototype.optionsAsChoices = function () {\n        var _this = this;\n        var choices = [];\n        this.element.querySelectorAll(':scope > option, :scope > optgroup').forEach(function (e) {\n            if (isHtmlOption(e)) {\n                choices.push(_this._optionToChoice(e));\n            }\n            else if (isHtmlOptgroup(e)) {\n                choices.push(_this._optgroupToChoice(e));\n            }\n            // todo: hr as empty optgroup, requires displaying empty opt-groups to be useful\n        });\n        return choices;\n    };\n    // eslint-disable-next-line class-methods-use-this\n    WrappedSelect.prototype._optionToChoice = function (option) {\n        // option.value returns the label if there is no value attribute, which can break legacy placeholder attribute support\n        if (!option.hasAttribute('value') && option.hasAttribute('placeholder')) {\n            option.setAttribute('value', '');\n            option.value = '';\n        }\n        return {\n            id: 0,\n            group: null,\n            score: 0,\n            rank: 0,\n            value: option.value,\n            // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/option\n            // This attribute is text for the label indicating the meaning of the option. If the `label` attribute isn't defined, its value is that of the element text content (ie `innerText`).\n            label: option.label,\n            element: option,\n            active: true,\n            // this returns true if nothing is selected on initial load, which will break placeholder support\n            selected: this.extractPlaceholder ? option.selected : option.hasAttribute('selected'),\n            disabled: option.disabled,\n            highlighted: false,\n            placeholder: this.extractPlaceholder && (!option.value || option.hasAttribute('placeholder')),\n            labelClass: typeof option.dataset.labelClass !== 'undefined' ? stringToHtmlClass(option.dataset.labelClass) : undefined,\n            labelDescription: typeof option.dataset.labelDescription !== 'undefined'\n                ? { trusted: option.dataset.labelDescription }\n                : undefined,\n            customProperties: parseCustomProperties(option.dataset.customProperties),\n        };\n    };\n    WrappedSelect.prototype._optgroupToChoice = function (optgroup) {\n        var _this = this;\n        var options = optgroup.querySelectorAll('option');\n        var choices = Array.from(options).map(function (option) { return _this._optionToChoice(option); });\n        return {\n            id: 0,\n            label: optgroup.label || '',\n            element: optgroup,\n            active: !!choices.length,\n            disabled: optgroup.disabled,\n            choices: choices,\n        };\n    };\n    return WrappedSelect;\n}(WrappedElement));\n\nvar DEFAULT_CLASSNAMES = {\n    containerOuter: ['choices'],\n    containerInner: ['choices__inner'],\n    input: ['choices__input'],\n    inputCloned: ['choices__input--cloned'],\n    list: ['choices__list'],\n    listItems: ['choices__list--multiple'],\n    listSingle: ['choices__list--single'],\n    listDropdown: ['choices__list--dropdown'],\n    item: ['choices__item'],\n    itemSelectable: ['choices__item--selectable'],\n    itemDisabled: ['choices__item--disabled'],\n    itemChoice: ['choices__item--choice'],\n    description: ['choices__description'],\n    placeholder: ['choices__placeholder'],\n    group: ['choices__group'],\n    groupHeading: ['choices__heading'],\n    button: ['choices__button'],\n    activeState: ['is-active'],\n    focusState: ['is-focused'],\n    openState: ['is-open'],\n    disabledState: ['is-disabled'],\n    highlightedState: ['is-highlighted'],\n    selectedState: ['is-selected'],\n    flippedState: ['is-flipped'],\n    loadingState: ['is-loading'],\n    invalidState: ['is-invalid'],\n    notice: ['choices__notice'],\n    addChoice: ['choices__item--selectable', 'add-choice'],\n    noResults: ['has-no-results'],\n    noChoices: ['has-no-choices'],\n};\nvar DEFAULT_CONFIG = {\n    items: [],\n    choices: [],\n    silent: false,\n    renderChoiceLimit: -1,\n    maxItemCount: -1,\n    closeDropdownOnSelect: 'auto',\n    singleModeForMultiSelect: false,\n    addChoices: false,\n    addItems: true,\n    addItemFilter: function (value) { return !!value && value !== ''; },\n    removeItems: true,\n    removeItemButton: false,\n    removeItemButtonAlignLeft: false,\n    editItems: false,\n    allowHTML: false,\n    allowHtmlUserInput: false,\n    duplicateItemsAllowed: true,\n    delimiter: ',',\n    paste: true,\n    searchEnabled: true,\n    searchChoices: true,\n    searchDisabledChoices: false,\n    searchFloor: 1,\n    searchResultLimit: 4,\n    searchFields: ['label', 'value'],\n    position: 'auto',\n    resetScrollPosition: true,\n    shouldSort: true,\n    shouldSortItems: false,\n    sorter: sortByAlpha,\n    shadowRoot: null,\n    placeholder: true,\n    placeholderValue: null,\n    searchPlaceholderValue: null,\n    prependValue: null,\n    appendValue: null,\n    renderSelectedChoices: 'auto',\n    searchRenderSelectedChoices: true,\n    loadingText: 'Loading...',\n    noResultsText: 'No results found',\n    noChoicesText: 'No choices to choose from',\n    itemSelectText: 'Press to select',\n    uniqueItemText: 'Only unique values can be added',\n    customAddItemText: 'Only values matching specific conditions can be added',\n    addItemText: function (value) { return \"Press Enter to add <b>\\\"\".concat(value, \"\\\"</b>\"); },\n    removeItemIconText: function () { return \"Remove item\"; },\n    removeItemLabelText: function (value, _valueRaw, i) {\n        return \"Remove item: \".concat(i ? sanitise(i.label) : value);\n    },\n    maxItemText: function (maxItemCount) { return \"Only \".concat(maxItemCount, \" values can be added\"); },\n    valueComparer: function (value1, value2) { return value1 === value2; },\n    fuseOptions: {\n        includeScore: true,\n    },\n    labelId: '',\n    callbackOnInit: null,\n    callbackOnCreateTemplates: null,\n    classNames: DEFAULT_CLASSNAMES,\n    appendGroupInSearch: false,\n};\n\nvar removeItem = function (item) {\n    var itemEl = item.itemEl;\n    if (itemEl) {\n        itemEl.remove();\n        item.itemEl = undefined;\n    }\n};\nfunction items(s, action, context) {\n    var state = s;\n    var update = true;\n    switch (action.type) {\n        case ActionType.ADD_ITEM: {\n            action.item.selected = true;\n            var el = action.item.element;\n            if (el) {\n                el.selected = true;\n                el.setAttribute('selected', '');\n            }\n            state.push(action.item);\n            break;\n        }\n        case ActionType.REMOVE_ITEM: {\n            action.item.selected = false;\n            var el = action.item.element;\n            if (el) {\n                el.selected = false;\n                el.removeAttribute('selected');\n                // For a select-one, if all options are deselected, the first item is selected. To set a black value, select.value needs to be set\n                var select = el.parentElement;\n                if (select && isHtmlSelectElement(select) && select.type === PassedElementTypes.SelectOne) {\n                    select.value = '';\n                }\n            }\n            // this is mixing concerns, but this is *so much faster*\n            removeItem(action.item);\n            state = state.filter(function (choice) { return choice.id !== action.item.id; });\n            break;\n        }\n        case ActionType.REMOVE_CHOICE: {\n            removeItem(action.choice);\n            state = state.filter(function (item) { return item.id !== action.choice.id; });\n            break;\n        }\n        case ActionType.HIGHLIGHT_ITEM: {\n            var highlighted = action.highlighted;\n            var item = state.find(function (obj) { return obj.id === action.item.id; });\n            if (item && item.highlighted !== highlighted) {\n                item.highlighted = highlighted;\n                if (context) {\n                    updateClassList(item, highlighted ? context.classNames.highlightedState : context.classNames.selectedState, highlighted ? context.classNames.selectedState : context.classNames.highlightedState);\n                }\n            }\n            break;\n        }\n        default: {\n            update = false;\n            break;\n        }\n    }\n    return { state: state, update: update };\n}\n\nfunction groups(s, action) {\n    var state = s;\n    var update = true;\n    switch (action.type) {\n        case ActionType.ADD_GROUP: {\n            state.push(action.group);\n            break;\n        }\n        case ActionType.CLEAR_CHOICES: {\n            state = [];\n            break;\n        }\n        default: {\n            update = false;\n            break;\n        }\n    }\n    return { state: state, update: update };\n}\n\n/* eslint-disable */\nfunction choices(s, action, context) {\n    var state = s;\n    var update = true;\n    switch (action.type) {\n        case ActionType.ADD_CHOICE: {\n            state.push(action.choice);\n            break;\n        }\n        case ActionType.REMOVE_CHOICE: {\n            action.choice.choiceEl = undefined;\n            if (action.choice.group) {\n                action.choice.group.choices = action.choice.group.choices.filter(function (obj) { return obj.id !== action.choice.id; });\n            }\n            state = state.filter(function (obj) { return obj.id !== action.choice.id; });\n            break;\n        }\n        case ActionType.ADD_ITEM:\n        case ActionType.REMOVE_ITEM: {\n            action.item.choiceEl = undefined;\n            break;\n        }\n        case ActionType.FILTER_CHOICES: {\n            // avoid O(n^2) algorithm complexity when searching/filtering choices\n            var scoreLookup_1 = [];\n            action.results.forEach(function (result) {\n                scoreLookup_1[result.item.id] = result;\n            });\n            state.forEach(function (choice) {\n                var result = scoreLookup_1[choice.id];\n                if (result !== undefined) {\n                    choice.score = result.score;\n                    choice.rank = result.rank;\n                    choice.active = true;\n                }\n                else {\n                    choice.score = 0;\n                    choice.rank = 0;\n                    choice.active = false;\n                }\n                if (context && context.appendGroupInSearch) {\n                    choice.choiceEl = undefined;\n                }\n            });\n            break;\n        }\n        case ActionType.ACTIVATE_CHOICES: {\n            state.forEach(function (choice) {\n                choice.active = action.active;\n                if (context && context.appendGroupInSearch) {\n                    choice.choiceEl = undefined;\n                }\n            });\n            break;\n        }\n        case ActionType.CLEAR_CHOICES: {\n            state = [];\n            break;\n        }\n        default: {\n            update = false;\n            break;\n        }\n    }\n    return { state: state, update: update };\n}\n\nvar reducers = {\n    groups: groups,\n    items: items,\n    choices: choices,\n};\nvar Store = /** @class */ (function () {\n    function Store(context) {\n        this._state = this.defaultState;\n        this._listeners = [];\n        this._txn = 0;\n        this._context = context;\n    }\n    Object.defineProperty(Store.prototype, \"defaultState\", {\n        // eslint-disable-next-line class-methods-use-this\n        get: function () {\n            return {\n                groups: [],\n                items: [],\n                choices: [],\n            };\n        },\n        enumerable: false,\n        configurable: true\n    });\n    // eslint-disable-next-line class-methods-use-this\n    Store.prototype.changeSet = function (init) {\n        return {\n            groups: init,\n            items: init,\n            choices: init,\n        };\n    };\n    Store.prototype.reset = function () {\n        this._state = this.defaultState;\n        var changes = this.changeSet(true);\n        if (this._txn) {\n            this._changeSet = changes;\n        }\n        else {\n            this._listeners.forEach(function (l) { return l(changes); });\n        }\n    };\n    Store.prototype.subscribe = function (onChange) {\n        this._listeners.push(onChange);\n        return this;\n    };\n    Store.prototype.dispatch = function (action) {\n        var _this = this;\n        var state = this._state;\n        var hasChanges = false;\n        var changes = this._changeSet || this.changeSet(false);\n        Object.keys(reducers).forEach(function (key) {\n            var stateUpdate = reducers[key](state[key], action, _this._context);\n            if (stateUpdate.update) {\n                hasChanges = true;\n                changes[key] = true;\n                state[key] = stateUpdate.state;\n            }\n        });\n        if (hasChanges) {\n            if (this._txn) {\n                this._changeSet = changes;\n            }\n            else {\n                this._listeners.forEach(function (l) { return l(changes); });\n            }\n        }\n    };\n    Store.prototype.withTxn = function (func) {\n        this._txn++;\n        try {\n            func();\n        }\n        finally {\n            this._txn = Math.max(0, this._txn - 1);\n            if (!this._txn) {\n                var changeSet_1 = this._changeSet;\n                if (changeSet_1) {\n                    this._changeSet = undefined;\n                    this._listeners.forEach(function (l) { return l(changeSet_1); });\n                }\n            }\n        }\n    };\n    Object.defineProperty(Store.prototype, \"state\", {\n        /**\n         * Get store object\n         */\n        get: function () {\n            return this._state;\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(Store.prototype, \"items\", {\n        /**\n         * Get items from store\n         */\n        get: function () {\n            return this.state.items;\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(Store.prototype, \"highlightedActiveItems\", {\n        /**\n         * Get highlighted items from store\n         */\n        get: function () {\n            return this.items.filter(function (item) { return item.active && item.highlighted; });\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(Store.prototype, \"choices\", {\n        /**\n         * Get choices from store\n         */\n        get: function () {\n            return this.state.choices;\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(Store.prototype, \"activeChoices\", {\n        /**\n         * Get active choices from store\n         */\n        get: function () {\n            return this.choices.filter(function (choice) { return choice.active; });\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(Store.prototype, \"searchableChoices\", {\n        /**\n         * Get choices that can be searched (excluding placeholders or disabled choices)\n         */\n        get: function () {\n            var context = this._context;\n            return this.choices.filter(function (choice) { return !choice.placeholder && (context.searchDisabledChoices || !choice.disabled); });\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(Store.prototype, \"groups\", {\n        /**\n         * Get groups from store\n         */\n        get: function () {\n            return this.state.groups;\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(Store.prototype, \"activeGroups\", {\n        /**\n         * Get active groups from store\n         */\n        get: function () {\n            var _this = this;\n            return this.state.groups.filter(function (group) {\n                var isActive = group.active && !group.disabled;\n                var hasActiveOptions = _this.state.choices.some(function (choice) { return choice.active && !choice.disabled; });\n                return isActive && hasActiveOptions;\n            }, []);\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Store.prototype.inTxn = function () {\n        return this._txn > 0;\n    };\n    /**\n     * Get single choice by it's ID\n     */\n    Store.prototype.getChoiceById = function (id) {\n        return this.activeChoices.find(function (choice) { return choice.id === id; });\n    };\n    /**\n     * Get group by group id\n     */\n    Store.prototype.getGroupById = function (id) {\n        return this.groups.find(function (group) { return group.id === id; });\n    };\n    return Store;\n}());\n\nvar NoticeTypes = {\n    noChoices: 'no-choices',\n    noResults: 'no-results',\n    addChoice: 'add-choice',\n    generic: '',\n};\n\nfunction _defineProperty(e, r, t) {\n  return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, {\n    value: t,\n    enumerable: true,\n    configurable: true,\n    writable: true\n  }) : e[r] = t, e;\n}\nfunction ownKeys(e, r) {\n  var t = Object.keys(e);\n  if (Object.getOwnPropertySymbols) {\n    var o = Object.getOwnPropertySymbols(e);\n    r && (o = o.filter(function (r) {\n      return Object.getOwnPropertyDescriptor(e, r).enumerable;\n    })), t.push.apply(t, o);\n  }\n  return t;\n}\nfunction _objectSpread2(e) {\n  for (var r = 1; r < arguments.length; r++) {\n    var t = null != arguments[r] ? arguments[r] : {};\n    r % 2 ? ownKeys(Object(t), true).forEach(function (r) {\n      _defineProperty(e, r, t[r]);\n    }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) {\n      Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));\n    });\n  }\n  return e;\n}\nfunction _toPrimitive(t, r) {\n  if (\"object\" != typeof t || !t) return t;\n  var e = t[Symbol.toPrimitive];\n  if (void 0 !== e) {\n    var i = e.call(t, r);\n    if (\"object\" != typeof i) return i;\n    throw new TypeError(\"@@toPrimitive must return a primitive value.\");\n  }\n  return (\"string\" === r ? String : Number)(t);\n}\nfunction _toPropertyKey(t) {\n  var i = _toPrimitive(t, \"string\");\n  return \"symbol\" == typeof i ? i : i + \"\";\n}\n\n/**\n * Fuse.js v7.0.0 - Lightweight fuzzy-search (http://fusejs.io)\n *\n * Copyright (c) 2023 Kiro Risk (http://kiro.me)\n * All Rights Reserved. Apache Software License 2.0\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n */\n\nfunction isArray(value) {\n  return !Array.isArray ? getTag(value) === '[object Array]' : Array.isArray(value);\n}\nfunction baseToString(value) {\n  // Exit early for strings to avoid a performance hit in some environments.\n  if (typeof value == 'string') {\n    return value;\n  }\n  let result = value + '';\n  return result == '0' && 1 / value == -Infinity ? '-0' : result;\n}\nfunction toString(value) {\n  return value == null ? '' : baseToString(value);\n}\nfunction isString(value) {\n  return typeof value === 'string';\n}\nfunction isNumber(value) {\n  return typeof value === 'number';\n}\n\n// Adapted from: https://github.com/lodash/lodash/blob/master/isBoolean.js\nfunction isBoolean(value) {\n  return value === true || value === false || isObjectLike(value) && getTag(value) == '[object Boolean]';\n}\nfunction isObject(value) {\n  return typeof value === 'object';\n}\n\n// Checks if `value` is object-like.\nfunction isObjectLike(value) {\n  return isObject(value) && value !== null;\n}\nfunction isDefined(value) {\n  return value !== undefined && value !== null;\n}\nfunction isBlank(value) {\n  return !value.trim().length;\n}\n\n// Gets the `toStringTag` of `value`.\n// Adapted from: https://github.com/lodash/lodash/blob/master/.internal/getTag.js\nfunction getTag(value) {\n  return value == null ? value === undefined ? '[object Undefined]' : '[object Null]' : Object.prototype.toString.call(value);\n}\nconst EXTENDED_SEARCH_UNAVAILABLE = 'Extended search is not available';\nconst LOGICAL_SEARCH_UNAVAILABLE = 'Logical search is not available';\nconst INCORRECT_INDEX_TYPE = \"Incorrect 'index' type\";\nconst LOGICAL_SEARCH_INVALID_QUERY_FOR_KEY = key => `Invalid value for key ${key}`;\nconst PATTERN_LENGTH_TOO_LARGE = max => `Pattern length exceeds max of ${max}.`;\nconst MISSING_KEY_PROPERTY = name => `Missing ${name} property in key`;\nconst INVALID_KEY_WEIGHT_VALUE = key => `Property 'weight' in key '${key}' must be a positive integer`;\nconst hasOwn = Object.prototype.hasOwnProperty;\nclass KeyStore {\n  constructor(keys) {\n    this._keys = [];\n    this._keyMap = {};\n    let totalWeight = 0;\n    keys.forEach(key => {\n      let obj = createKey(key);\n      this._keys.push(obj);\n      this._keyMap[obj.id] = obj;\n      totalWeight += obj.weight;\n    });\n\n    // Normalize weights so that their sum is equal to 1\n    this._keys.forEach(key => {\n      key.weight /= totalWeight;\n    });\n  }\n  get(keyId) {\n    return this._keyMap[keyId];\n  }\n  keys() {\n    return this._keys;\n  }\n  toJSON() {\n    return JSON.stringify(this._keys);\n  }\n}\nfunction createKey(key) {\n  let path = null;\n  let id = null;\n  let src = null;\n  let weight = 1;\n  let getFn = null;\n  if (isString(key) || isArray(key)) {\n    src = key;\n    path = createKeyPath(key);\n    id = createKeyId(key);\n  } else {\n    if (!hasOwn.call(key, 'name')) {\n      throw new Error(MISSING_KEY_PROPERTY('name'));\n    }\n    const name = key.name;\n    src = name;\n    if (hasOwn.call(key, 'weight')) {\n      weight = key.weight;\n      if (weight <= 0) {\n        throw new Error(INVALID_KEY_WEIGHT_VALUE(name));\n      }\n    }\n    path = createKeyPath(name);\n    id = createKeyId(name);\n    getFn = key.getFn;\n  }\n  return {\n    path,\n    id,\n    weight,\n    src,\n    getFn\n  };\n}\nfunction createKeyPath(key) {\n  return isArray(key) ? key : key.split('.');\n}\nfunction createKeyId(key) {\n  return isArray(key) ? key.join('.') : key;\n}\nfunction get(obj, path) {\n  let list = [];\n  let arr = false;\n  const deepGet = (obj, path, index) => {\n    if (!isDefined(obj)) {\n      return;\n    }\n    if (!path[index]) {\n      // If there's no path left, we've arrived at the object we care about.\n      list.push(obj);\n    } else {\n      let key = path[index];\n      const value = obj[key];\n      if (!isDefined(value)) {\n        return;\n      }\n\n      // If we're at the last value in the path, and if it's a string/number/bool,\n      // add it to the list\n      if (index === path.length - 1 && (isString(value) || isNumber(value) || isBoolean(value))) {\n        list.push(toString(value));\n      } else if (isArray(value)) {\n        arr = true;\n        // Search each item in the array.\n        for (let i = 0, len = value.length; i < len; i += 1) {\n          deepGet(value[i], path, index + 1);\n        }\n      } else if (path.length) {\n        // An object. Recurse further.\n        deepGet(value, path, index + 1);\n      }\n    }\n  };\n\n  // Backwards compatibility (since path used to be a string)\n  deepGet(obj, isString(path) ? path.split('.') : path, 0);\n  return arr ? list : list[0];\n}\nconst MatchOptions = {\n  // Whether the matches should be included in the result set. When `true`, each record in the result\n  // set will include the indices of the matched characters.\n  // These can consequently be used for highlighting purposes.\n  includeMatches: false,\n  // When `true`, the matching function will continue to the end of a search pattern even if\n  // a perfect match has already been located in the string.\n  findAllMatches: false,\n  // Minimum number of characters that must be matched before a result is considered a match\n  minMatchCharLength: 1\n};\nconst BasicOptions = {\n  // When `true`, the algorithm continues searching to the end of the input even if a perfect\n  // match is found before the end of the same input.\n  isCaseSensitive: false,\n  // When true, the matching function will continue to the end of a search pattern even if\n  includeScore: false,\n  // List of properties that will be searched. This also supports nested properties.\n  keys: [],\n  // Whether to sort the result list, by score\n  shouldSort: true,\n  // Default sort function: sort by ascending score, ascending index\n  sortFn: (a, b) => a.score === b.score ? a.idx < b.idx ? -1 : 1 : a.score < b.score ? -1 : 1\n};\nconst FuzzyOptions = {\n  // Approximately where in the text is the pattern expected to be found?\n  location: 0,\n  // At what point does the match algorithm give up. A threshold of '0.0' requires a perfect match\n  // (of both letters and location), a threshold of '1.0' would match anything.\n  threshold: 0.6,\n  // Determines how close the match must be to the fuzzy location (specified above).\n  // An exact letter match which is 'distance' characters away from the fuzzy location\n  // would score as a complete mismatch. A distance of '0' requires the match be at\n  // the exact location specified, a threshold of '1000' would require a perfect match\n  // to be within 800 characters of the fuzzy location to be found using a 0.8 threshold.\n  distance: 100\n};\nconst AdvancedOptions = {\n  // When `true`, it enables the use of unix-like search commands\n  useExtendedSearch: false,\n  // The get function to use when fetching an object's properties.\n  // The default will search nested paths *ie foo.bar.baz*\n  getFn: get,\n  // When `true`, search will ignore `location` and `distance`, so it won't matter\n  // where in the string the pattern appears.\n  // More info: https://fusejs.io/concepts/scoring-theory.html#fuzziness-score\n  ignoreLocation: false,\n  // When `true`, the calculation for the relevance score (used for sorting) will\n  // ignore the field-length norm.\n  // More info: https://fusejs.io/concepts/scoring-theory.html#field-length-norm\n  ignoreFieldNorm: false,\n  // The weight to determine how much field length norm effects scoring.\n  fieldNormWeight: 1\n};\nvar Config = _objectSpread2(_objectSpread2(_objectSpread2(_objectSpread2({}, BasicOptions), MatchOptions), FuzzyOptions), AdvancedOptions);\nconst SPACE = /[^ ]+/g;\n\n// Field-length norm: the shorter the field, the higher the weight.\n// Set to 3 decimals to reduce index size.\nfunction norm(weight = 1, mantissa = 3) {\n  const cache = new Map();\n  const m = Math.pow(10, mantissa);\n  return {\n    get(value) {\n      const numTokens = value.match(SPACE).length;\n      if (cache.has(numTokens)) {\n        return cache.get(numTokens);\n      }\n\n      // Default function is 1/sqrt(x), weight makes that variable\n      const norm = 1 / Math.pow(numTokens, 0.5 * weight);\n\n      // In place of `toFixed(mantissa)`, for faster computation\n      const n = parseFloat(Math.round(norm * m) / m);\n      cache.set(numTokens, n);\n      return n;\n    },\n    clear() {\n      cache.clear();\n    }\n  };\n}\nclass FuseIndex {\n  constructor({\n    getFn = Config.getFn,\n    fieldNormWeight = Config.fieldNormWeight\n  } = {}) {\n    this.norm = norm(fieldNormWeight, 3);\n    this.getFn = getFn;\n    this.isCreated = false;\n    this.setIndexRecords();\n  }\n  setSources(docs = []) {\n    this.docs = docs;\n  }\n  setIndexRecords(records = []) {\n    this.records = records;\n  }\n  setKeys(keys = []) {\n    this.keys = keys;\n    this._keysMap = {};\n    keys.forEach((key, idx) => {\n      this._keysMap[key.id] = idx;\n    });\n  }\n  create() {\n    if (this.isCreated || !this.docs.length) {\n      return;\n    }\n    this.isCreated = true;\n\n    // List is Array<String>\n    if (isString(this.docs[0])) {\n      this.docs.forEach((doc, docIndex) => {\n        this._addString(doc, docIndex);\n      });\n    } else {\n      // List is Array<Object>\n      this.docs.forEach((doc, docIndex) => {\n        this._addObject(doc, docIndex);\n      });\n    }\n    this.norm.clear();\n  }\n  // Adds a doc to the end of the index\n  add(doc) {\n    const idx = this.size();\n    if (isString(doc)) {\n      this._addString(doc, idx);\n    } else {\n      this._addObject(doc, idx);\n    }\n  }\n  // Removes the doc at the specified index of the index\n  removeAt(idx) {\n    this.records.splice(idx, 1);\n\n    // Change ref index of every subsquent doc\n    for (let i = idx, len = this.size(); i < len; i += 1) {\n      this.records[i].i -= 1;\n    }\n  }\n  getValueForItemAtKeyId(item, keyId) {\n    return item[this._keysMap[keyId]];\n  }\n  size() {\n    return this.records.length;\n  }\n  _addString(doc, docIndex) {\n    if (!isDefined(doc) || isBlank(doc)) {\n      return;\n    }\n    let record = {\n      v: doc,\n      i: docIndex,\n      n: this.norm.get(doc)\n    };\n    this.records.push(record);\n  }\n  _addObject(doc, docIndex) {\n    let record = {\n      i: docIndex,\n      $: {}\n    };\n\n    // Iterate over every key (i.e, path), and fetch the value at that key\n    this.keys.forEach((key, keyIndex) => {\n      let value = key.getFn ? key.getFn(doc) : this.getFn(doc, key.path);\n      if (!isDefined(value)) {\n        return;\n      }\n      if (isArray(value)) {\n        let subRecords = [];\n        const stack = [{\n          nestedArrIndex: -1,\n          value\n        }];\n        while (stack.length) {\n          const {\n            nestedArrIndex,\n            value\n          } = stack.pop();\n          if (!isDefined(value)) {\n            continue;\n          }\n          if (isString(value) && !isBlank(value)) {\n            let subRecord = {\n              v: value,\n              i: nestedArrIndex,\n              n: this.norm.get(value)\n            };\n            subRecords.push(subRecord);\n          } else if (isArray(value)) {\n            value.forEach((item, k) => {\n              stack.push({\n                nestedArrIndex: k,\n                value: item\n              });\n            });\n          } else ;\n        }\n        record.$[keyIndex] = subRecords;\n      } else if (isString(value) && !isBlank(value)) {\n        let subRecord = {\n          v: value,\n          n: this.norm.get(value)\n        };\n        record.$[keyIndex] = subRecord;\n      }\n    });\n    this.records.push(record);\n  }\n  toJSON() {\n    return {\n      keys: this.keys,\n      records: this.records\n    };\n  }\n}\nfunction createIndex(keys, docs, {\n  getFn = Config.getFn,\n  fieldNormWeight = Config.fieldNormWeight\n} = {}) {\n  const myIndex = new FuseIndex({\n    getFn,\n    fieldNormWeight\n  });\n  myIndex.setKeys(keys.map(createKey));\n  myIndex.setSources(docs);\n  myIndex.create();\n  return myIndex;\n}\nfunction parseIndex(data, {\n  getFn = Config.getFn,\n  fieldNormWeight = Config.fieldNormWeight\n} = {}) {\n  const {\n    keys,\n    records\n  } = data;\n  const myIndex = new FuseIndex({\n    getFn,\n    fieldNormWeight\n  });\n  myIndex.setKeys(keys);\n  myIndex.setIndexRecords(records);\n  return myIndex;\n}\nfunction computeScore$1(pattern, {\n  errors = 0,\n  currentLocation = 0,\n  expectedLocation = 0,\n  distance = Config.distance,\n  ignoreLocation = Config.ignoreLocation\n} = {}) {\n  const accuracy = errors / pattern.length;\n  if (ignoreLocation) {\n    return accuracy;\n  }\n  const proximity = Math.abs(expectedLocation - currentLocation);\n  if (!distance) {\n    // Dodge divide by zero error.\n    return proximity ? 1.0 : accuracy;\n  }\n  return accuracy + proximity / distance;\n}\nfunction convertMaskToIndices(matchmask = [], minMatchCharLength = Config.minMatchCharLength) {\n  let indices = [];\n  let start = -1;\n  let end = -1;\n  let i = 0;\n  for (let len = matchmask.length; i < len; i += 1) {\n    let match = matchmask[i];\n    if (match && start === -1) {\n      start = i;\n    } else if (!match && start !== -1) {\n      end = i - 1;\n      if (end - start + 1 >= minMatchCharLength) {\n        indices.push([start, end]);\n      }\n      start = -1;\n    }\n  }\n\n  // (i-1 - start) + 1 => i - start\n  if (matchmask[i - 1] && i - start >= minMatchCharLength) {\n    indices.push([start, i - 1]);\n  }\n  return indices;\n}\n\n// Machine word size\nconst MAX_BITS = 32;\nfunction search(text, pattern, patternAlphabet, {\n  location = Config.location,\n  distance = Config.distance,\n  threshold = Config.threshold,\n  findAllMatches = Config.findAllMatches,\n  minMatchCharLength = Config.minMatchCharLength,\n  includeMatches = Config.includeMatches,\n  ignoreLocation = Config.ignoreLocation\n} = {}) {\n  if (pattern.length > MAX_BITS) {\n    throw new Error(PATTERN_LENGTH_TOO_LARGE(MAX_BITS));\n  }\n  const patternLen = pattern.length;\n  // Set starting location at beginning text and initialize the alphabet.\n  const textLen = text.length;\n  // Handle the case when location > text.length\n  const expectedLocation = Math.max(0, Math.min(location, textLen));\n  // Highest score beyond which we give up.\n  let currentThreshold = threshold;\n  // Is there a nearby exact match? (speedup)\n  let bestLocation = expectedLocation;\n\n  // Performance: only computer matches when the minMatchCharLength > 1\n  // OR if `includeMatches` is true.\n  const computeMatches = minMatchCharLength > 1 || includeMatches;\n  // A mask of the matches, used for building the indices\n  const matchMask = computeMatches ? Array(textLen) : [];\n  let index;\n\n  // Get all exact matches, here for speed up\n  while ((index = text.indexOf(pattern, bestLocation)) > -1) {\n    let score = computeScore$1(pattern, {\n      currentLocation: index,\n      expectedLocation,\n      distance,\n      ignoreLocation\n    });\n    currentThreshold = Math.min(score, currentThreshold);\n    bestLocation = index + patternLen;\n    if (computeMatches) {\n      let i = 0;\n      while (i < patternLen) {\n        matchMask[index + i] = 1;\n        i += 1;\n      }\n    }\n  }\n\n  // Reset the best location\n  bestLocation = -1;\n  let lastBitArr = [];\n  let finalScore = 1;\n  let binMax = patternLen + textLen;\n  const mask = 1 << patternLen - 1;\n  for (let i = 0; i < patternLen; i += 1) {\n    // Scan for the best match; each iteration allows for one more error.\n    // Run a binary search to determine how far from the match location we can stray\n    // at this error level.\n    let binMin = 0;\n    let binMid = binMax;\n    while (binMin < binMid) {\n      const score = computeScore$1(pattern, {\n        errors: i,\n        currentLocation: expectedLocation + binMid,\n        expectedLocation,\n        distance,\n        ignoreLocation\n      });\n      if (score <= currentThreshold) {\n        binMin = binMid;\n      } else {\n        binMax = binMid;\n      }\n      binMid = Math.floor((binMax - binMin) / 2 + binMin);\n    }\n\n    // Use the result from this iteration as the maximum for the next.\n    binMax = binMid;\n    let start = Math.max(1, expectedLocation - binMid + 1);\n    let finish = findAllMatches ? textLen : Math.min(expectedLocation + binMid, textLen) + patternLen;\n\n    // Initialize the bit array\n    let bitArr = Array(finish + 2);\n    bitArr[finish + 1] = (1 << i) - 1;\n    for (let j = finish; j >= start; j -= 1) {\n      let currentLocation = j - 1;\n      let charMatch = patternAlphabet[text.charAt(currentLocation)];\n      if (computeMatches) {\n        // Speed up: quick bool to int conversion (i.e, `charMatch ? 1 : 0`)\n        matchMask[currentLocation] = +!!charMatch;\n      }\n\n      // First pass: exact match\n      bitArr[j] = (bitArr[j + 1] << 1 | 1) & charMatch;\n\n      // Subsequent passes: fuzzy match\n      if (i) {\n        bitArr[j] |= (lastBitArr[j + 1] | lastBitArr[j]) << 1 | 1 | lastBitArr[j + 1];\n      }\n      if (bitArr[j] & mask) {\n        finalScore = computeScore$1(pattern, {\n          errors: i,\n          currentLocation,\n          expectedLocation,\n          distance,\n          ignoreLocation\n        });\n\n        // This match will almost certainly be better than any existing match.\n        // But check anyway.\n        if (finalScore <= currentThreshold) {\n          // Indeed it is\n          currentThreshold = finalScore;\n          bestLocation = currentLocation;\n\n          // Already passed `loc`, downhill from here on in.\n          if (bestLocation <= expectedLocation) {\n            break;\n          }\n\n          // When passing `bestLocation`, don't exceed our current distance from `expectedLocation`.\n          start = Math.max(1, 2 * expectedLocation - bestLocation);\n        }\n      }\n    }\n\n    // No hope for a (better) match at greater error levels.\n    const score = computeScore$1(pattern, {\n      errors: i + 1,\n      currentLocation: expectedLocation,\n      expectedLocation,\n      distance,\n      ignoreLocation\n    });\n    if (score > currentThreshold) {\n      break;\n    }\n    lastBitArr = bitArr;\n  }\n  const result = {\n    isMatch: bestLocation >= 0,\n    // Count exact matches (those with a score of 0) to be \"almost\" exact\n    score: Math.max(0.001, finalScore)\n  };\n  if (computeMatches) {\n    const indices = convertMaskToIndices(matchMask, minMatchCharLength);\n    if (!indices.length) {\n      result.isMatch = false;\n    } else if (includeMatches) {\n      result.indices = indices;\n    }\n  }\n  return result;\n}\nfunction createPatternAlphabet(pattern) {\n  let mask = {};\n  for (let i = 0, len = pattern.length; i < len; i += 1) {\n    const char = pattern.charAt(i);\n    mask[char] = (mask[char] || 0) | 1 << len - i - 1;\n  }\n  return mask;\n}\nclass BitapSearch {\n  constructor(pattern, {\n    location = Config.location,\n    threshold = Config.threshold,\n    distance = Config.distance,\n    includeMatches = Config.includeMatches,\n    findAllMatches = Config.findAllMatches,\n    minMatchCharLength = Config.minMatchCharLength,\n    isCaseSensitive = Config.isCaseSensitive,\n    ignoreLocation = Config.ignoreLocation\n  } = {}) {\n    this.options = {\n      location,\n      threshold,\n      distance,\n      includeMatches,\n      findAllMatches,\n      minMatchCharLength,\n      isCaseSensitive,\n      ignoreLocation\n    };\n    this.pattern = isCaseSensitive ? pattern : pattern.toLowerCase();\n    this.chunks = [];\n    if (!this.pattern.length) {\n      return;\n    }\n    const addChunk = (pattern, startIndex) => {\n      this.chunks.push({\n        pattern,\n        alphabet: createPatternAlphabet(pattern),\n        startIndex\n      });\n    };\n    const len = this.pattern.length;\n    if (len > MAX_BITS) {\n      let i = 0;\n      const remainder = len % MAX_BITS;\n      const end = len - remainder;\n      while (i < end) {\n        addChunk(this.pattern.substr(i, MAX_BITS), i);\n        i += MAX_BITS;\n      }\n      if (remainder) {\n        const startIndex = len - MAX_BITS;\n        addChunk(this.pattern.substr(startIndex), startIndex);\n      }\n    } else {\n      addChunk(this.pattern, 0);\n    }\n  }\n  searchIn(text) {\n    const {\n      isCaseSensitive,\n      includeMatches\n    } = this.options;\n    if (!isCaseSensitive) {\n      text = text.toLowerCase();\n    }\n\n    // Exact match\n    if (this.pattern === text) {\n      let result = {\n        isMatch: true,\n        score: 0\n      };\n      if (includeMatches) {\n        result.indices = [[0, text.length - 1]];\n      }\n      return result;\n    }\n\n    // Otherwise, use Bitap algorithm\n    const {\n      location,\n      distance,\n      threshold,\n      findAllMatches,\n      minMatchCharLength,\n      ignoreLocation\n    } = this.options;\n    let allIndices = [];\n    let totalScore = 0;\n    let hasMatches = false;\n    this.chunks.forEach(({\n      pattern,\n      alphabet,\n      startIndex\n    }) => {\n      const {\n        isMatch,\n        score,\n        indices\n      } = search(text, pattern, alphabet, {\n        location: location + startIndex,\n        distance,\n        threshold,\n        findAllMatches,\n        minMatchCharLength,\n        includeMatches,\n        ignoreLocation\n      });\n      if (isMatch) {\n        hasMatches = true;\n      }\n      totalScore += score;\n      if (isMatch && indices) {\n        allIndices = [...allIndices, ...indices];\n      }\n    });\n    let result = {\n      isMatch: hasMatches,\n      score: hasMatches ? totalScore / this.chunks.length : 1\n    };\n    if (hasMatches && includeMatches) {\n      result.indices = allIndices;\n    }\n    return result;\n  }\n}\nconst registeredSearchers = [];\nfunction createSearcher(pattern, options) {\n  for (let i = 0, len = registeredSearchers.length; i < len; i += 1) {\n    let searcherClass = registeredSearchers[i];\n    if (searcherClass.condition(pattern, options)) {\n      return new searcherClass(pattern, options);\n    }\n  }\n  return new BitapSearch(pattern, options);\n}\nconst LogicalOperator = {\n  AND: '$and',\n  OR: '$or'\n};\nconst KeyType = {\n  PATH: '$path',\n  PATTERN: '$val'\n};\nconst isExpression = query => !!(query[LogicalOperator.AND] || query[LogicalOperator.OR]);\nconst isPath = query => !!query[KeyType.PATH];\nconst isLeaf = query => !isArray(query) && isObject(query) && !isExpression(query);\nconst convertToExplicit = query => ({\n  [LogicalOperator.AND]: Object.keys(query).map(key => ({\n    [key]: query[key]\n  }))\n});\n\n// When `auto` is `true`, the parse function will infer and initialize and add\n// the appropriate `Searcher` instance\nfunction parse(query, options, {\n  auto = true\n} = {}) {\n  const next = query => {\n    let keys = Object.keys(query);\n    const isQueryPath = isPath(query);\n    if (!isQueryPath && keys.length > 1 && !isExpression(query)) {\n      return next(convertToExplicit(query));\n    }\n    if (isLeaf(query)) {\n      const key = isQueryPath ? query[KeyType.PATH] : keys[0];\n      const pattern = isQueryPath ? query[KeyType.PATTERN] : query[key];\n      if (!isString(pattern)) {\n        throw new Error(LOGICAL_SEARCH_INVALID_QUERY_FOR_KEY(key));\n      }\n      const obj = {\n        keyId: createKeyId(key),\n        pattern\n      };\n      if (auto) {\n        obj.searcher = createSearcher(pattern, options);\n      }\n      return obj;\n    }\n    let node = {\n      children: [],\n      operator: keys[0]\n    };\n    keys.forEach(key => {\n      const value = query[key];\n      if (isArray(value)) {\n        value.forEach(item => {\n          node.children.push(next(item));\n        });\n      }\n    });\n    return node;\n  };\n  if (!isExpression(query)) {\n    query = convertToExplicit(query);\n  }\n  return next(query);\n}\n\n// Practical scoring function\nfunction computeScore(results, {\n  ignoreFieldNorm = Config.ignoreFieldNorm\n}) {\n  results.forEach(result => {\n    let totalScore = 1;\n    result.matches.forEach(({\n      key,\n      norm,\n      score\n    }) => {\n      const weight = key ? key.weight : null;\n      totalScore *= Math.pow(score === 0 && weight ? Number.EPSILON : score, (weight || 1) * (ignoreFieldNorm ? 1 : norm));\n    });\n    result.score = totalScore;\n  });\n}\nfunction transformMatches(result, data) {\n  const matches = result.matches;\n  data.matches = [];\n  if (!isDefined(matches)) {\n    return;\n  }\n  matches.forEach(match => {\n    if (!isDefined(match.indices) || !match.indices.length) {\n      return;\n    }\n    const {\n      indices,\n      value\n    } = match;\n    let obj = {\n      indices,\n      value\n    };\n    if (match.key) {\n      obj.key = match.key.src;\n    }\n    if (match.idx > -1) {\n      obj.refIndex = match.idx;\n    }\n    data.matches.push(obj);\n  });\n}\nfunction transformScore(result, data) {\n  data.score = result.score;\n}\nfunction format(results, docs, {\n  includeMatches = Config.includeMatches,\n  includeScore = Config.includeScore\n} = {}) {\n  const transformers = [];\n  if (includeMatches) transformers.push(transformMatches);\n  if (includeScore) transformers.push(transformScore);\n  return results.map(result => {\n    const {\n      idx\n    } = result;\n    const data = {\n      item: docs[idx],\n      refIndex: idx\n    };\n    if (transformers.length) {\n      transformers.forEach(transformer => {\n        transformer(result, data);\n      });\n    }\n    return data;\n  });\n}\nclass Fuse {\n  constructor(docs, options = {}, index) {\n    this.options = _objectSpread2(_objectSpread2({}, Config), options);\n    if (this.options.useExtendedSearch && true) {\n      throw new Error(EXTENDED_SEARCH_UNAVAILABLE);\n    }\n    this._keyStore = new KeyStore(this.options.keys);\n    this.setCollection(docs, index);\n  }\n  setCollection(docs, index) {\n    this._docs = docs;\n    if (index && !(index instanceof FuseIndex)) {\n      throw new Error(INCORRECT_INDEX_TYPE);\n    }\n    this._myIndex = index || createIndex(this.options.keys, this._docs, {\n      getFn: this.options.getFn,\n      fieldNormWeight: this.options.fieldNormWeight\n    });\n  }\n  add(doc) {\n    if (!isDefined(doc)) {\n      return;\n    }\n    this._docs.push(doc);\n    this._myIndex.add(doc);\n  }\n  remove(predicate = ( /* doc, idx */) => false) {\n    const results = [];\n    for (let i = 0, len = this._docs.length; i < len; i += 1) {\n      const doc = this._docs[i];\n      if (predicate(doc, i)) {\n        this.removeAt(i);\n        i -= 1;\n        len -= 1;\n        results.push(doc);\n      }\n    }\n    return results;\n  }\n  removeAt(idx) {\n    this._docs.splice(idx, 1);\n    this._myIndex.removeAt(idx);\n  }\n  getIndex() {\n    return this._myIndex;\n  }\n  search(query, {\n    limit = -1\n  } = {}) {\n    const {\n      includeMatches,\n      includeScore,\n      shouldSort,\n      sortFn,\n      ignoreFieldNorm\n    } = this.options;\n    let results = isString(query) ? isString(this._docs[0]) ? this._searchStringList(query) : this._searchObjectList(query) : this._searchLogical(query);\n    computeScore(results, {\n      ignoreFieldNorm\n    });\n    if (shouldSort) {\n      results.sort(sortFn);\n    }\n    if (isNumber(limit) && limit > -1) {\n      results = results.slice(0, limit);\n    }\n    return format(results, this._docs, {\n      includeMatches,\n      includeScore\n    });\n  }\n  _searchStringList(query) {\n    const searcher = createSearcher(query, this.options);\n    const {\n      records\n    } = this._myIndex;\n    const results = [];\n\n    // Iterate over every string in the index\n    records.forEach(({\n      v: text,\n      i: idx,\n      n: norm\n    }) => {\n      if (!isDefined(text)) {\n        return;\n      }\n      const {\n        isMatch,\n        score,\n        indices\n      } = searcher.searchIn(text);\n      if (isMatch) {\n        results.push({\n          item: text,\n          idx,\n          matches: [{\n            score,\n            value: text,\n            norm,\n            indices\n          }]\n        });\n      }\n    });\n    return results;\n  }\n  _searchLogical(query) {\n    {\n      throw new Error(LOGICAL_SEARCH_UNAVAILABLE);\n    }\n  }\n  _searchObjectList(query) {\n    const searcher = createSearcher(query, this.options);\n    const {\n      keys,\n      records\n    } = this._myIndex;\n    const results = [];\n\n    // List is Array<Object>\n    records.forEach(({\n      $: item,\n      i: idx\n    }) => {\n      if (!isDefined(item)) {\n        return;\n      }\n      let matches = [];\n\n      // Iterate over every key (i.e, path), and fetch the value at that key\n      keys.forEach((key, keyIndex) => {\n        matches.push(...this._findMatches({\n          key,\n          value: item[keyIndex],\n          searcher\n        }));\n      });\n      if (matches.length) {\n        results.push({\n          idx,\n          item,\n          matches\n        });\n      }\n    });\n    return results;\n  }\n  _findMatches({\n    key,\n    value,\n    searcher\n  }) {\n    if (!isDefined(value)) {\n      return [];\n    }\n    let matches = [];\n    if (isArray(value)) {\n      value.forEach(({\n        v: text,\n        i: idx,\n        n: norm\n      }) => {\n        if (!isDefined(text)) {\n          return;\n        }\n        const {\n          isMatch,\n          score,\n          indices\n        } = searcher.searchIn(text);\n        if (isMatch) {\n          matches.push({\n            score,\n            key,\n            value: text,\n            idx,\n            norm,\n            indices\n          });\n        }\n      });\n    } else {\n      const {\n        v: text,\n        n: norm\n      } = value;\n      const {\n        isMatch,\n        score,\n        indices\n      } = searcher.searchIn(text);\n      if (isMatch) {\n        matches.push({\n          score,\n          key,\n          value: text,\n          norm,\n          indices\n        });\n      }\n    }\n    return matches;\n  }\n}\nFuse.version = '7.0.0';\nFuse.createIndex = createIndex;\nFuse.parseIndex = parseIndex;\nFuse.config = Config;\n{\n  Fuse.parseQuery = parse;\n}\n\nvar SearchByFuse = /** @class */ (function () {\n    function SearchByFuse(config) {\n        this._haystack = [];\n        this._fuseOptions = __assign(__assign({}, config.fuseOptions), { keys: __spreadArray([], config.searchFields, true), includeMatches: true });\n    }\n    SearchByFuse.prototype.index = function (data) {\n        this._haystack = data;\n        if (this._fuse) {\n            this._fuse.setCollection(data);\n        }\n    };\n    SearchByFuse.prototype.reset = function () {\n        this._haystack = [];\n        this._fuse = undefined;\n    };\n    SearchByFuse.prototype.isEmptyIndex = function () {\n        return !this._haystack.length;\n    };\n    SearchByFuse.prototype.search = function (needle) {\n        if (!this._fuse) {\n            {\n                this._fuse = new Fuse(this._haystack, this._fuseOptions);\n            }\n        }\n        var results = this._fuse.search(needle);\n        return results.map(function (value, i) {\n            return {\n                item: value.item,\n                score: value.score || 0,\n                rank: i + 1, // If value.score is used for sorting, this can create non-stable sorts!\n            };\n        });\n    };\n    return SearchByFuse;\n}());\n\nfunction getSearcher(config) {\n    {\n        return new SearchByFuse(config);\n    }\n}\n\n/**\n * Helpers to create HTML elements used by Choices\n * Can be overridden by providing `callbackOnCreateTemplates` option.\n * `Choices.defaults.templates` allows access to the default template methods from `callbackOnCreateTemplates`\n */\nvar isEmptyObject = function (obj) {\n    // eslint-disable-next-line no-restricted-syntax\n    for (var prop in obj) {\n        if (Object.prototype.hasOwnProperty.call(obj, prop)) {\n            return false;\n        }\n    }\n    return true;\n};\nvar assignCustomProperties = function (el, choice, withCustomProperties) {\n    var dataset = el.dataset;\n    var customProperties = choice.customProperties, labelClass = choice.labelClass, labelDescription = choice.labelDescription;\n    if (labelClass) {\n        dataset.labelClass = getClassNames(labelClass).join(' ');\n    }\n    if (labelDescription) {\n        dataset.labelDescription = unwrapStringForRaw(labelDescription);\n    }\n    if (withCustomProperties && customProperties) {\n        if (typeof customProperties === 'string') {\n            dataset.customProperties = customProperties;\n        }\n        else if (typeof customProperties === 'object' && !isEmptyObject(customProperties)) {\n            dataset.customProperties = JSON.stringify(customProperties);\n        }\n    }\n};\nvar addAriaLabel = function (docRoot, id, element) {\n    var label = id && docRoot.querySelector(\"label[for='\".concat(id, \"']\"));\n    var text = label && label.innerText;\n    if (text) {\n        element.setAttribute('aria-label', text);\n    }\n};\nvar templates = {\n    containerOuter: function (_a, dir, isSelectElement, isSelectOneElement, searchEnabled, passedElementType, labelId) {\n        var containerOuter = _a.classNames.containerOuter;\n        var div = document.createElement('div');\n        addClassesToElement(div, containerOuter);\n        div.dataset.type = passedElementType;\n        if (dir) {\n            div.dir = dir;\n        }\n        if (isSelectOneElement) {\n            div.tabIndex = 0;\n        }\n        if (isSelectElement) {\n            div.setAttribute('role', searchEnabled ? 'combobox' : 'listbox');\n            if (searchEnabled) {\n                div.setAttribute('aria-autocomplete', 'list');\n            }\n            else if (!labelId) {\n                addAriaLabel(this._docRoot, this.passedElement.element.id, div);\n            }\n            div.setAttribute('aria-haspopup', 'true');\n            div.setAttribute('aria-expanded', 'false');\n        }\n        if (labelId) {\n            div.setAttribute('aria-labelledby', labelId);\n        }\n        return div;\n    },\n    containerInner: function (_a) {\n        var containerInner = _a.classNames.containerInner;\n        var div = document.createElement('div');\n        addClassesToElement(div, containerInner);\n        return div;\n    },\n    itemList: function (_a, isSelectOneElement) {\n        var searchEnabled = _a.searchEnabled, _b = _a.classNames, list = _b.list, listSingle = _b.listSingle, listItems = _b.listItems;\n        var div = document.createElement('div');\n        addClassesToElement(div, list);\n        addClassesToElement(div, isSelectOneElement ? listSingle : listItems);\n        if (this._isSelectElement && searchEnabled) {\n            div.setAttribute('role', 'listbox');\n        }\n        return div;\n    },\n    placeholder: function (_a, value) {\n        var allowHTML = _a.allowHTML, placeholder = _a.classNames.placeholder;\n        var div = document.createElement('div');\n        addClassesToElement(div, placeholder);\n        setElementHtml(div, allowHTML, value);\n        return div;\n    },\n    item: function (_a, choice, removeItemButton) {\n        var allowHTML = _a.allowHTML, removeItemButtonAlignLeft = _a.removeItemButtonAlignLeft, removeItemIconText = _a.removeItemIconText, removeItemLabelText = _a.removeItemLabelText, _b = _a.classNames, item = _b.item, button = _b.button, highlightedState = _b.highlightedState, itemSelectable = _b.itemSelectable, placeholder = _b.placeholder;\n        var rawValue = unwrapStringForRaw(choice.value);\n        var div = document.createElement('div');\n        addClassesToElement(div, item);\n        if (choice.labelClass) {\n            var spanLabel = document.createElement('span');\n            setElementHtml(spanLabel, allowHTML, choice.label);\n            addClassesToElement(spanLabel, choice.labelClass);\n            div.appendChild(spanLabel);\n        }\n        else {\n            setElementHtml(div, allowHTML, choice.label);\n        }\n        div.dataset.item = '';\n        div.dataset.id = choice.id;\n        div.dataset.value = rawValue;\n        assignCustomProperties(div, choice, true);\n        if (choice.disabled || this.containerOuter.isDisabled) {\n            div.setAttribute('aria-disabled', 'true');\n        }\n        if (this._isSelectElement) {\n            div.setAttribute('aria-selected', 'true');\n            div.setAttribute('role', 'option');\n        }\n        if (choice.placeholder) {\n            addClassesToElement(div, placeholder);\n            div.dataset.placeholder = '';\n        }\n        addClassesToElement(div, choice.highlighted ? highlightedState : itemSelectable);\n        if (removeItemButton) {\n            if (choice.disabled) {\n                removeClassesFromElement(div, itemSelectable);\n            }\n            div.dataset.deletable = '';\n            var removeButton = document.createElement('button');\n            removeButton.type = 'button';\n            addClassesToElement(removeButton, button);\n            var eventChoice = getChoiceForOutput(choice);\n            setElementHtml(removeButton, true, resolveNoticeFunction(removeItemIconText, choice.value, eventChoice));\n            var REMOVE_ITEM_LABEL = resolveNoticeFunction(removeItemLabelText, choice.value, eventChoice);\n            if (REMOVE_ITEM_LABEL) {\n                removeButton.setAttribute('aria-label', REMOVE_ITEM_LABEL);\n            }\n            removeButton.dataset.button = '';\n            if (removeItemButtonAlignLeft) {\n                div.insertAdjacentElement('afterbegin', removeButton);\n            }\n            else {\n                div.appendChild(removeButton);\n            }\n        }\n        return div;\n    },\n    choiceList: function (_a, isSelectOneElement) {\n        var list = _a.classNames.list;\n        var div = document.createElement('div');\n        addClassesToElement(div, list);\n        if (!isSelectOneElement) {\n            div.setAttribute('aria-multiselectable', 'true');\n        }\n        div.setAttribute('role', 'listbox');\n        return div;\n    },\n    choiceGroup: function (_a, _b) {\n        var allowHTML = _a.allowHTML, _c = _a.classNames, group = _c.group, groupHeading = _c.groupHeading, itemDisabled = _c.itemDisabled;\n        var id = _b.id, label = _b.label, disabled = _b.disabled;\n        var rawLabel = unwrapStringForRaw(label);\n        var div = document.createElement('div');\n        addClassesToElement(div, group);\n        if (disabled) {\n            addClassesToElement(div, itemDisabled);\n        }\n        div.setAttribute('role', 'group');\n        div.dataset.group = '';\n        div.dataset.id = id;\n        div.dataset.value = rawLabel;\n        if (disabled) {\n            div.setAttribute('aria-disabled', 'true');\n        }\n        var heading = document.createElement('div');\n        addClassesToElement(heading, groupHeading);\n        setElementHtml(heading, allowHTML, label || '');\n        div.appendChild(heading);\n        return div;\n    },\n    choice: function (_a, choice, selectText, groupName) {\n        var allowHTML = _a.allowHTML, _b = _a.classNames, item = _b.item, itemChoice = _b.itemChoice, itemSelectable = _b.itemSelectable, selectedState = _b.selectedState, itemDisabled = _b.itemDisabled, description = _b.description, placeholder = _b.placeholder;\n        // eslint-disable-next-line prefer-destructuring\n        var label = choice.label;\n        var rawValue = unwrapStringForRaw(choice.value);\n        var div = document.createElement('div');\n        div.id = choice.elementId;\n        addClassesToElement(div, item);\n        addClassesToElement(div, itemChoice);\n        if (groupName && typeof label === 'string') {\n            label = escapeForTemplate(allowHTML, label);\n            label += \" (\".concat(groupName, \")\");\n            label = { trusted: label };\n        }\n        var describedBy = div;\n        if (choice.labelClass) {\n            var spanLabel = document.createElement('span');\n            setElementHtml(spanLabel, allowHTML, label);\n            addClassesToElement(spanLabel, choice.labelClass);\n            describedBy = spanLabel;\n            div.appendChild(spanLabel);\n        }\n        else {\n            setElementHtml(div, allowHTML, label);\n        }\n        if (choice.labelDescription) {\n            var descId = \"\".concat(choice.elementId, \"-description\");\n            describedBy.setAttribute('aria-describedby', descId);\n            var spanDesc = document.createElement('span');\n            setElementHtml(spanDesc, allowHTML, choice.labelDescription);\n            spanDesc.id = descId;\n            addClassesToElement(spanDesc, description);\n            div.appendChild(spanDesc);\n        }\n        if (choice.selected) {\n            addClassesToElement(div, selectedState);\n        }\n        if (choice.placeholder) {\n            addClassesToElement(div, placeholder);\n        }\n        div.setAttribute('role', choice.group ? 'treeitem' : 'option');\n        div.dataset.choice = '';\n        div.dataset.id = choice.id;\n        div.dataset.value = rawValue;\n        if (selectText) {\n            div.dataset.selectText = selectText;\n        }\n        if (choice.group) {\n            div.dataset.groupId = \"\".concat(choice.group.id);\n        }\n        assignCustomProperties(div, choice, false);\n        if (choice.disabled) {\n            addClassesToElement(div, itemDisabled);\n            div.dataset.choiceDisabled = '';\n            div.setAttribute('aria-disabled', 'true');\n        }\n        else {\n            addClassesToElement(div, itemSelectable);\n            div.dataset.choiceSelectable = '';\n            div.setAttribute('aria-selected', choice.selected ? 'true' : 'false');\n        }\n        return div;\n    },\n    input: function (_a, placeholderValue) {\n        var _b = _a.classNames, input = _b.input, inputCloned = _b.inputCloned, labelId = _a.labelId;\n        var inp = document.createElement('input');\n        inp.type = 'search';\n        addClassesToElement(inp, input);\n        addClassesToElement(inp, inputCloned);\n        inp.autocomplete = 'off';\n        inp.autocapitalize = 'off';\n        inp.spellcheck = false;\n        inp.setAttribute('aria-autocomplete', 'list');\n        if (placeholderValue) {\n            inp.setAttribute('aria-label', placeholderValue);\n        }\n        else if (!labelId) {\n            addAriaLabel(this._docRoot, this.passedElement.element.id, inp);\n        }\n        return inp;\n    },\n    dropdown: function (_a) {\n        var _b = _a.classNames, list = _b.list, listDropdown = _b.listDropdown;\n        var div = document.createElement('div');\n        addClassesToElement(div, list);\n        addClassesToElement(div, listDropdown);\n        div.setAttribute('aria-expanded', 'false');\n        return div;\n    },\n    notice: function (_a, innerHTML, type) {\n        var _b = _a.classNames, item = _b.item, itemChoice = _b.itemChoice, addChoice = _b.addChoice, noResults = _b.noResults, noChoices = _b.noChoices, noticeItem = _b.notice;\n        if (type === void 0) { type = NoticeTypes.generic; }\n        var notice = document.createElement('div');\n        setElementHtml(notice, true, innerHTML);\n        addClassesToElement(notice, item);\n        addClassesToElement(notice, itemChoice);\n        addClassesToElement(notice, noticeItem);\n        // eslint-disable-next-line default-case\n        switch (type) {\n            case NoticeTypes.addChoice:\n                addClassesToElement(notice, addChoice);\n                break;\n            case NoticeTypes.noResults:\n                addClassesToElement(notice, noResults);\n                break;\n            case NoticeTypes.noChoices:\n                addClassesToElement(notice, noChoices);\n                break;\n        }\n        if (type === NoticeTypes.addChoice) {\n            notice.dataset.choiceSelectable = '';\n            notice.dataset.choice = '';\n        }\n        return notice;\n    },\n    option: function (choice) {\n        // HtmlOptionElement's label value does not support HTML, so the avoid double escaping unwrap the untrusted string.\n        var labelValue = unwrapStringForRaw(choice.label);\n        var opt = new Option(labelValue, choice.value, false, choice.selected);\n        assignCustomProperties(opt, choice, true);\n        opt.disabled = choice.disabled;\n        if (choice.selected) {\n            opt.setAttribute('selected', '');\n        }\n        return opt;\n    },\n};\n\n/** @see {@link http://browserhacks.com/#hack-acea075d0ac6954f275a70023906050c} */\nvar IS_IE11 = '-ms-scroll-limit' in document.documentElement.style &&\n    '-ms-ime-align' in document.documentElement.style;\nvar USER_DEFAULTS = {};\nvar parseDataSetId = function (element) {\n    if (!element) {\n        return undefined;\n    }\n    return element.dataset.id ? parseInt(element.dataset.id, 10) : undefined;\n};\nvar selectableChoiceIdentifier = '[data-choice-selectable]';\n/**\n * Choices\n * @author Josh Johnson<josh@joshuajohnson.co.uk>\n */\nvar Choices = /** @class */ (function () {\n    function Choices(element, userConfig) {\n        if (element === void 0) { element = '[data-choice]'; }\n        if (userConfig === void 0) { userConfig = {}; }\n        var _this = this;\n        this.initialisedOK = undefined;\n        this._hasNonChoicePlaceholder = false;\n        this._lastAddedChoiceId = 0;\n        this._lastAddedGroupId = 0;\n        var defaults = Choices.defaults;\n        this.config = __assign(__assign(__assign({}, defaults.allOptions), defaults.options), userConfig);\n        ObjectsInConfig.forEach(function (key) {\n            _this.config[key] = __assign(__assign(__assign({}, defaults.allOptions[key]), defaults.options[key]), userConfig[key]);\n        });\n        var config = this.config;\n        if (!config.silent) {\n            this._validateConfig();\n        }\n        var docRoot = config.shadowRoot || document.documentElement;\n        this._docRoot = docRoot;\n        var passedElement = typeof element === 'string' ? docRoot.querySelector(element) : element;\n        if (!passedElement ||\n            typeof passedElement !== 'object' ||\n            !(isHtmlInputElement(passedElement) || isHtmlSelectElement(passedElement))) {\n            if (!passedElement && typeof element === 'string') {\n                throw TypeError(\"Selector \".concat(element, \" failed to find an element\"));\n            }\n            throw TypeError(\"Expected one of the following types text|select-one|select-multiple\");\n        }\n        var elementType = passedElement.type;\n        var isText = elementType === PassedElementTypes.Text;\n        if (isText || config.maxItemCount !== 1) {\n            config.singleModeForMultiSelect = false;\n        }\n        if (config.singleModeForMultiSelect) {\n            elementType = PassedElementTypes.SelectMultiple;\n        }\n        var isSelectOne = elementType === PassedElementTypes.SelectOne;\n        var isSelectMultiple = elementType === PassedElementTypes.SelectMultiple;\n        var isSelect = isSelectOne || isSelectMultiple;\n        this._elementType = elementType;\n        this._isTextElement = isText;\n        this._isSelectOneElement = isSelectOne;\n        this._isSelectMultipleElement = isSelectMultiple;\n        this._isSelectElement = isSelectOne || isSelectMultiple;\n        this._canAddUserChoices = (isText && config.addItems) || (isSelect && config.addChoices);\n        if (typeof config.renderSelectedChoices !== 'boolean') {\n            config.renderSelectedChoices = config.renderSelectedChoices === 'always' || isSelectOne;\n        }\n        if (config.closeDropdownOnSelect === 'auto') {\n            config.closeDropdownOnSelect = isText || isSelectOne || config.singleModeForMultiSelect;\n        }\n        else {\n            config.closeDropdownOnSelect = coerceBool(config.closeDropdownOnSelect);\n        }\n        if (config.placeholder) {\n            if (config.placeholderValue) {\n                this._hasNonChoicePlaceholder = true;\n            }\n            else if (passedElement.dataset.placeholder) {\n                this._hasNonChoicePlaceholder = true;\n                config.placeholderValue = passedElement.dataset.placeholder;\n            }\n        }\n        if (userConfig.addItemFilter && typeof userConfig.addItemFilter !== 'function') {\n            var re = userConfig.addItemFilter instanceof RegExp ? userConfig.addItemFilter : new RegExp(userConfig.addItemFilter);\n            config.addItemFilter = re.test.bind(re);\n        }\n        if (this._isTextElement) {\n            this.passedElement = new WrappedInput({\n                element: passedElement,\n                classNames: config.classNames,\n            });\n        }\n        else {\n            var selectEl = passedElement;\n            this.passedElement = new WrappedSelect({\n                element: selectEl,\n                classNames: config.classNames,\n                template: function (data) { return _this._templates.option(data); },\n                extractPlaceholder: config.placeholder && !this._hasNonChoicePlaceholder,\n            });\n        }\n        this.initialised = false;\n        this._store = new Store(config);\n        this._currentValue = '';\n        config.searchEnabled = !isText && config.searchEnabled;\n        this._canSearch = config.searchEnabled;\n        this._isScrollingOnIe = false;\n        this._highlightPosition = 0;\n        this._wasTap = true;\n        this._placeholderValue = this._generatePlaceholderValue();\n        this._baseId = generateId(passedElement, 'choices-');\n        /**\n         * setting direction in cases where it's explicitly set on passedElement\n         * or when calculated direction is different from the document\n         */\n        this._direction = passedElement.dir;\n        if (!this._direction) {\n            var elementDirection = window.getComputedStyle(passedElement).direction;\n            var documentDirection = window.getComputedStyle(document.documentElement).direction;\n            if (elementDirection !== documentDirection) {\n                this._direction = elementDirection;\n            }\n        }\n        this._idNames = {\n            itemChoice: 'item-choice',\n        };\n        this._templates = defaults.templates;\n        this._render = this._render.bind(this);\n        this._onFocus = this._onFocus.bind(this);\n        this._onBlur = this._onBlur.bind(this);\n        this._onKeyUp = this._onKeyUp.bind(this);\n        this._onKeyDown = this._onKeyDown.bind(this);\n        this._onInput = this._onInput.bind(this);\n        this._onClick = this._onClick.bind(this);\n        this._onTouchMove = this._onTouchMove.bind(this);\n        this._onTouchEnd = this._onTouchEnd.bind(this);\n        this._onMouseDown = this._onMouseDown.bind(this);\n        this._onMouseOver = this._onMouseOver.bind(this);\n        this._onFormReset = this._onFormReset.bind(this);\n        this._onSelectKey = this._onSelectKey.bind(this);\n        this._onEnterKey = this._onEnterKey.bind(this);\n        this._onEscapeKey = this._onEscapeKey.bind(this);\n        this._onDirectionKey = this._onDirectionKey.bind(this);\n        this._onDeleteKey = this._onDeleteKey.bind(this);\n        this._onChange = this._onChange.bind(this);\n        this._onInvalid = this._onInvalid.bind(this);\n        // If element has already been initialised with Choices, fail silently\n        if (this.passedElement.isActive) {\n            if (!config.silent) {\n                console.warn('Trying to initialise Choices on element already initialised', { element: element });\n            }\n            this.initialised = true;\n            this.initialisedOK = false;\n            return;\n        }\n        // Let's go\n        this.init();\n        // preserve the selected item list after setup for form reset\n        this._initialItems = this._store.items.map(function (choice) { return choice.value; });\n    }\n    Object.defineProperty(Choices, \"defaults\", {\n        get: function () {\n            return Object.preventExtensions({\n                get options() {\n                    return USER_DEFAULTS;\n                },\n                get allOptions() {\n                    return DEFAULT_CONFIG;\n                },\n                get templates() {\n                    return templates;\n                },\n            });\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Choices.prototype.init = function () {\n        if (this.initialised || this.initialisedOK !== undefined) {\n            return;\n        }\n        this._searcher = getSearcher(this.config);\n        this._loadChoices();\n        this._createTemplates();\n        this._createElements();\n        this._createStructure();\n        if ((this._isTextElement && !this.config.addItems) ||\n            this.passedElement.element.hasAttribute('disabled') ||\n            !!this.passedElement.element.closest('fieldset:disabled')) {\n            this.disable();\n        }\n        else {\n            this.enable();\n            this._addEventListeners();\n        }\n        // should be triggered **after** disabled state to avoid additional re-draws\n        this._initStore();\n        this.initialised = true;\n        this.initialisedOK = true;\n        var callbackOnInit = this.config.callbackOnInit;\n        // Run callback if it is a function\n        if (typeof callbackOnInit === 'function') {\n            callbackOnInit.call(this);\n        }\n    };\n    Choices.prototype.destroy = function () {\n        if (!this.initialised) {\n            return;\n        }\n        this._removeEventListeners();\n        this.passedElement.reveal();\n        this.containerOuter.unwrap(this.passedElement.element);\n        this._store._listeners = []; // prevents select/input value being wiped\n        this.clearStore(false);\n        this._stopSearch();\n        this._templates = Choices.defaults.templates;\n        this.initialised = false;\n        this.initialisedOK = undefined;\n    };\n    Choices.prototype.enable = function () {\n        if (this.passedElement.isDisabled) {\n            this.passedElement.enable();\n        }\n        if (this.containerOuter.isDisabled) {\n            this._addEventListeners();\n            this.input.enable();\n            this.containerOuter.enable();\n        }\n        return this;\n    };\n    Choices.prototype.disable = function () {\n        if (!this.passedElement.isDisabled) {\n            this.passedElement.disable();\n        }\n        if (!this.containerOuter.isDisabled) {\n            this._removeEventListeners();\n            this.input.disable();\n            this.containerOuter.disable();\n        }\n        return this;\n    };\n    Choices.prototype.highlightItem = function (item, runEvent) {\n        if (runEvent === void 0) { runEvent = true; }\n        if (!item || !item.id) {\n            return this;\n        }\n        var choice = this._store.items.find(function (c) { return c.id === item.id; });\n        if (!choice || choice.highlighted) {\n            return this;\n        }\n        this._store.dispatch(highlightItem(choice, true));\n        if (runEvent) {\n            this.passedElement.triggerEvent(EventType.highlightItem, getChoiceForOutput(choice));\n        }\n        return this;\n    };\n    Choices.prototype.unhighlightItem = function (item, runEvent) {\n        if (runEvent === void 0) { runEvent = true; }\n        if (!item || !item.id) {\n            return this;\n        }\n        var choice = this._store.items.find(function (c) { return c.id === item.id; });\n        if (!choice || !choice.highlighted) {\n            return this;\n        }\n        this._store.dispatch(highlightItem(choice, false));\n        if (runEvent) {\n            this.passedElement.triggerEvent(EventType.unhighlightItem, getChoiceForOutput(choice));\n        }\n        return this;\n    };\n    Choices.prototype.highlightAll = function () {\n        var _this = this;\n        this._store.withTxn(function () {\n            _this._store.items.forEach(function (item) {\n                if (!item.highlighted) {\n                    _this._store.dispatch(highlightItem(item, true));\n                    _this.passedElement.triggerEvent(EventType.highlightItem, getChoiceForOutput(item));\n                }\n            });\n        });\n        return this;\n    };\n    Choices.prototype.unhighlightAll = function () {\n        var _this = this;\n        this._store.withTxn(function () {\n            _this._store.items.forEach(function (item) {\n                if (item.highlighted) {\n                    _this._store.dispatch(highlightItem(item, false));\n                    _this.passedElement.triggerEvent(EventType.highlightItem, getChoiceForOutput(item));\n                }\n            });\n        });\n        return this;\n    };\n    Choices.prototype.removeActiveItemsByValue = function (value) {\n        var _this = this;\n        this._store.withTxn(function () {\n            _this._store.items.filter(function (item) { return item.value === value; }).forEach(function (item) { return _this._removeItem(item); });\n        });\n        return this;\n    };\n    Choices.prototype.removeActiveItems = function (excludedId) {\n        var _this = this;\n        this._store.withTxn(function () {\n            _this._store.items.filter(function (_a) {\n                var id = _a.id;\n                return id !== excludedId;\n            }).forEach(function (item) { return _this._removeItem(item); });\n        });\n        return this;\n    };\n    Choices.prototype.removeHighlightedItems = function (runEvent) {\n        var _this = this;\n        if (runEvent === void 0) { runEvent = false; }\n        this._store.withTxn(function () {\n            _this._store.highlightedActiveItems.forEach(function (item) {\n                _this._removeItem(item);\n                // If this action was performed by the user\n                // trigger the event\n                if (runEvent) {\n                    _this._triggerChange(item.value);\n                }\n            });\n        });\n        return this;\n    };\n    Choices.prototype.showDropdown = function (preventInputFocus) {\n        var _this = this;\n        if (this.dropdown.isActive) {\n            return this;\n        }\n        if (preventInputFocus === undefined) {\n            // eslint-disable-next-line no-param-reassign\n            preventInputFocus = !this._canSearch;\n        }\n        requestAnimationFrame(function () {\n            _this.dropdown.show();\n            var rect = _this.dropdown.element.getBoundingClientRect();\n            _this.containerOuter.open(rect.bottom, rect.height);\n            if (!preventInputFocus) {\n                _this.input.focus();\n            }\n            _this.passedElement.triggerEvent(EventType.showDropdown);\n            var activeElement = _this.choiceList.element.querySelector(getClassNamesSelector(_this.config.classNames.selectedState));\n            if (activeElement !== null && !isScrolledIntoView(activeElement, _this.choiceList.element)) {\n                // We use the native scrollIntoView function instead of choiceList.scrollToChildElement to avoid animated scroll.\n                activeElement.scrollIntoView();\n            }\n        });\n        return this;\n    };\n    Choices.prototype.hideDropdown = function (preventInputBlur) {\n        var _this = this;\n        if (!this.dropdown.isActive) {\n            return this;\n        }\n        this._removeHighlightedChoices();\n        requestAnimationFrame(function () {\n            _this.dropdown.hide();\n            _this.containerOuter.close();\n            if (!preventInputBlur && _this._canSearch) {\n                _this.input.removeActiveDescendant();\n                _this.input.blur();\n            }\n            _this.passedElement.triggerEvent(EventType.hideDropdown);\n        });\n        return this;\n    };\n    Choices.prototype.getValue = function (valueOnly) {\n        var values = this._store.items.map(function (item) {\n            return (valueOnly ? item.value : getChoiceForOutput(item));\n        });\n        return this._isSelectOneElement || this.config.singleModeForMultiSelect ? values[0] : values;\n    };\n    Choices.prototype.setValue = function (items) {\n        var _this = this;\n        if (!this.initialisedOK) {\n            this._warnChoicesInitFailed('setValue');\n            return this;\n        }\n        this._store.withTxn(function () {\n            items.forEach(function (value) {\n                if (value) {\n                    _this._addChoice(mapInputToChoice(value, false));\n                }\n            });\n        });\n        // @todo integrate with Store\n        this._searcher.reset();\n        return this;\n    };\n    Choices.prototype.setChoiceByValue = function (value) {\n        var _this = this;\n        if (!this.initialisedOK) {\n            this._warnChoicesInitFailed('setChoiceByValue');\n            return this;\n        }\n        if (this._isTextElement) {\n            return this;\n        }\n        this._store.withTxn(function () {\n            // If only one value has been passed, convert to array\n            var choiceValue = Array.isArray(value) ? value : [value];\n            // Loop through each value and\n            choiceValue.forEach(function (val) { return _this._findAndSelectChoiceByValue(val); });\n            _this.unhighlightAll();\n        });\n        // @todo integrate with Store\n        this._searcher.reset();\n        return this;\n    };\n    /**\n     * Set choices of select input via an array of objects (or function that returns array of object or promise of it),\n     * a value field name and a label field name.\n     * This behaves the same as passing items via the choices option but can be called after initialising Choices.\n     * This can also be used to add groups of choices (see example 2); Optionally pass a true `replaceChoices` value to remove any existing choices.\n     * Optionally pass a `customProperties` object to add additional data to your choices (useful when searching/filtering etc).\n     *\n     * **Input types affected:** select-one, select-multiple\n     *\n     * @example\n     * ```js\n     * const example = new Choices(element);\n     *\n     * example.setChoices([\n     *   {value: 'One', label: 'Label One', disabled: true},\n     *   {value: 'Two', label: 'Label Two', selected: true},\n     *   {value: 'Three', label: 'Label Three'},\n     * ], 'value', 'label', false);\n     * ```\n     *\n     * @example\n     * ```js\n     * const example = new Choices(element);\n     *\n     * example.setChoices(async () => {\n     *   try {\n     *      const items = await fetch('/items');\n     *      return items.json()\n     *   } catch(err) {\n     *      console.error(err)\n     *   }\n     * });\n     * ```\n     *\n     * @example\n     * ```js\n     * const example = new Choices(element);\n     *\n     * example.setChoices([{\n     *   label: 'Group one',\n     *   id: 1,\n     *   disabled: false,\n     *   choices: [\n     *     {value: 'Child One', label: 'Child One', selected: true},\n     *     {value: 'Child Two', label: 'Child Two',  disabled: true},\n     *     {value: 'Child Three', label: 'Child Three'},\n     *   ]\n     * },\n     * {\n     *   label: 'Group two',\n     *   id: 2,\n     *   disabled: false,\n     *   choices: [\n     *     {value: 'Child Four', label: 'Child Four', disabled: true},\n     *     {value: 'Child Five', label: 'Child Five'},\n     *     {value: 'Child Six', label: 'Child Six', customProperties: {\n     *       description: 'Custom description about child six',\n     *       random: 'Another random custom property'\n     *     }},\n     *   ]\n     * }], 'value', 'label', false);\n     * ```\n     */\n    Choices.prototype.setChoices = function (choicesArrayOrFetcher, value, label, replaceChoices, clearSearchFlag, replaceItems) {\n        var _this = this;\n        if (choicesArrayOrFetcher === void 0) { choicesArrayOrFetcher = []; }\n        if (value === void 0) { value = 'value'; }\n        if (label === void 0) { label = 'label'; }\n        if (replaceChoices === void 0) { replaceChoices = false; }\n        if (clearSearchFlag === void 0) { clearSearchFlag = true; }\n        if (replaceItems === void 0) { replaceItems = false; }\n        if (!this.initialisedOK) {\n            this._warnChoicesInitFailed('setChoices');\n            return this;\n        }\n        if (!this._isSelectElement) {\n            throw new TypeError(\"setChoices can't be used with INPUT based Choices\");\n        }\n        if (typeof value !== 'string' || !value) {\n            throw new TypeError(\"value parameter must be a name of 'value' field in passed objects\");\n        }\n        if (typeof choicesArrayOrFetcher === 'function') {\n            // it's a choices fetcher function\n            var fetcher_1 = choicesArrayOrFetcher(this);\n            if (typeof Promise === 'function' && fetcher_1 instanceof Promise) {\n                // that's a promise\n                // eslint-disable-next-line no-promise-executor-return\n                return new Promise(function (resolve) { return requestAnimationFrame(resolve); })\n                    .then(function () { return _this._handleLoadingState(true); })\n                    .then(function () { return fetcher_1; })\n                    .then(function (data) {\n                    return _this.setChoices(data, value, label, replaceChoices, clearSearchFlag, replaceItems);\n                })\n                    .catch(function (err) {\n                    if (!_this.config.silent) {\n                        console.error(err);\n                    }\n                })\n                    .then(function () { return _this._handleLoadingState(false); })\n                    .then(function () { return _this; });\n            }\n            // function returned something else than promise, let's check if it's an array of choices\n            if (!Array.isArray(fetcher_1)) {\n                throw new TypeError(\".setChoices first argument function must return either array of choices or Promise, got: \".concat(typeof fetcher_1));\n            }\n            // recursion with results, it's sync and choices were cleared already\n            return this.setChoices(fetcher_1, value, label, false);\n        }\n        if (!Array.isArray(choicesArrayOrFetcher)) {\n            throw new TypeError(\".setChoices must be called either with array of choices with a function resulting into Promise of array of choices\");\n        }\n        this.containerOuter.removeLoadingState();\n        this._store.withTxn(function () {\n            if (clearSearchFlag) {\n                _this._isSearching = false;\n            }\n            // Clear choices if needed\n            if (replaceChoices) {\n                _this.clearChoices(true, replaceItems);\n            }\n            var isDefaultValue = value === 'value';\n            var isDefaultLabel = label === 'label';\n            choicesArrayOrFetcher.forEach(function (groupOrChoice) {\n                if ('choices' in groupOrChoice) {\n                    var group = groupOrChoice;\n                    if (!isDefaultLabel) {\n                        group = __assign(__assign({}, group), { label: group[label] });\n                    }\n                    _this._addGroup(mapInputToChoice(group, true));\n                }\n                else {\n                    var choice = groupOrChoice;\n                    if (!isDefaultLabel || !isDefaultValue) {\n                        choice = __assign(__assign({}, choice), { value: choice[value], label: choice[label] });\n                    }\n                    var choiceFull = mapInputToChoice(choice, false);\n                    _this._addChoice(choiceFull);\n                    if (choiceFull.placeholder && !_this._hasNonChoicePlaceholder) {\n                        _this._placeholderValue = unwrapStringForEscaped(choiceFull.label);\n                    }\n                }\n            });\n            _this.unhighlightAll();\n        });\n        // @todo integrate with Store\n        this._searcher.reset();\n        return this;\n    };\n    Choices.prototype.refresh = function (withEvents, selectFirstOption, deselectAll) {\n        var _this = this;\n        if (withEvents === void 0) { withEvents = false; }\n        if (selectFirstOption === void 0) { selectFirstOption = false; }\n        if (deselectAll === void 0) { deselectAll = false; }\n        if (!this._isSelectElement) {\n            if (!this.config.silent) {\n                console.warn('refresh method can only be used on choices backed by a <select> element');\n            }\n            return this;\n        }\n        this._store.withTxn(function () {\n            var choicesFromOptions = _this.passedElement.optionsAsChoices();\n            // Build the list of items which require preserving\n            var existingItems = {};\n            if (!deselectAll) {\n                _this._store.items.forEach(function (choice) {\n                    if (choice.id && choice.active && choice.selected) {\n                        existingItems[choice.value] = true;\n                    }\n                });\n            }\n            _this.clearStore(false);\n            var updateChoice = function (choice) {\n                if (deselectAll) {\n                    _this._store.dispatch(removeItem$1(choice));\n                }\n                else if (existingItems[choice.value]) {\n                    choice.selected = true;\n                }\n            };\n            choicesFromOptions.forEach(function (groupOrChoice) {\n                if ('choices' in groupOrChoice) {\n                    groupOrChoice.choices.forEach(updateChoice);\n                    return;\n                }\n                updateChoice(groupOrChoice);\n            });\n            /* @todo only generate add events for the added options instead of all\n            if (withEvents) {\n              items.forEach((choice) => {\n                if (existingItems[choice.value]) {\n                  this.passedElement.triggerEvent(\n                    EventType.removeItem,\n                    this._getChoiceForEvent(choice),\n                  );\n                }\n              });\n            }\n            */\n            // load new choices & items\n            _this._addPredefinedChoices(choicesFromOptions, selectFirstOption, withEvents);\n            // re-do search if required\n            if (_this._isSearching) {\n                _this._searchChoices(_this.input.value);\n            }\n        });\n        return this;\n    };\n    Choices.prototype.removeChoice = function (value) {\n        var choice = this._store.choices.find(function (c) { return c.value === value; });\n        if (!choice) {\n            return this;\n        }\n        this._clearNotice();\n        this._store.dispatch(removeChoice(choice));\n        // @todo integrate with Store\n        this._searcher.reset();\n        if (choice.selected) {\n            this.passedElement.triggerEvent(EventType.removeItem, getChoiceForOutput(choice));\n        }\n        return this;\n    };\n    Choices.prototype.clearChoices = function (clearOptions, clearItems) {\n        var _this = this;\n        if (clearOptions === void 0) { clearOptions = true; }\n        if (clearItems === void 0) { clearItems = false; }\n        if (clearOptions) {\n            if (clearItems) {\n                this.passedElement.element.replaceChildren('');\n            }\n            else {\n                this.passedElement.element.querySelectorAll(':not([selected])').forEach(function (el) {\n                    el.remove();\n                });\n            }\n        }\n        this.itemList.element.replaceChildren('');\n        this.choiceList.element.replaceChildren('');\n        this._clearNotice();\n        this._store.withTxn(function () {\n            var items = clearItems ? [] : _this._store.items;\n            _this._store.reset();\n            items.forEach(function (item) {\n                _this._store.dispatch(addChoice(item));\n                _this._store.dispatch(addItem(item));\n            });\n        });\n        // @todo integrate with Store\n        this._searcher.reset();\n        return this;\n    };\n    Choices.prototype.clearStore = function (clearOptions) {\n        if (clearOptions === void 0) { clearOptions = true; }\n        this.clearChoices(clearOptions, true);\n        this._stopSearch();\n        this._lastAddedChoiceId = 0;\n        this._lastAddedGroupId = 0;\n        return this;\n    };\n    Choices.prototype.clearInput = function () {\n        var shouldSetInputWidth = !this._isSelectOneElement;\n        this.input.clear(shouldSetInputWidth);\n        this._stopSearch();\n        return this;\n    };\n    Choices.prototype._validateConfig = function () {\n        var config = this.config;\n        var invalidConfigOptions = diff(config, DEFAULT_CONFIG);\n        if (invalidConfigOptions.length) {\n            console.warn('Unknown config option(s) passed', invalidConfigOptions.join(', '));\n        }\n        if (config.allowHTML && config.allowHtmlUserInput) {\n            if (config.addItems) {\n                console.warn('Warning: allowHTML/allowHtmlUserInput/addItems all being true is strongly not recommended and may lead to XSS attacks');\n            }\n            if (config.addChoices) {\n                console.warn('Warning: allowHTML/allowHtmlUserInput/addChoices all being true is strongly not recommended and may lead to XSS attacks');\n            }\n        }\n    };\n    Choices.prototype._render = function (changes) {\n        if (changes === void 0) { changes = { choices: true, groups: true, items: true }; }\n        if (this._store.inTxn()) {\n            return;\n        }\n        if (this._isSelectElement) {\n            if (changes.choices || changes.groups) {\n                this._renderChoices();\n            }\n        }\n        if (changes.items) {\n            this._renderItems();\n        }\n    };\n    Choices.prototype._renderChoices = function () {\n        var _this = this;\n        if (!this._canAddItems()) {\n            return; // block rendering choices if the input limit is reached.\n        }\n        var _a = this, config = _a.config, isSearching = _a._isSearching;\n        var _b = this._store, activeGroups = _b.activeGroups, activeChoices = _b.activeChoices;\n        var renderLimit = isSearching ? config.searchResultLimit : config.renderChoiceLimit;\n        if (this._isSelectElement) {\n            var backingOptions = activeChoices.filter(function (choice) { return !choice.element; });\n            if (backingOptions.length) {\n                this.passedElement.addOptions(backingOptions);\n            }\n        }\n        var fragment = document.createDocumentFragment();\n        var renderableChoices = function (choices) {\n            return choices.filter(function (choice) {\n                return !choice.placeholder &&\n                    (isSearching\n                        ? (config.searchRenderSelectedChoices || !choice.selected) && !!choice.rank\n                        : config.renderSelectedChoices || !choice.selected);\n            });\n        };\n        var showLabel = config.appendGroupInSearch && isSearching;\n        var selectableChoices = false;\n        var highlightedEl = null;\n        var renderChoices = function (choices, withinGroup) {\n            if (isSearching) {\n                // sortByRank is used to ensure stable sorting, as scores are non-unique\n                // this additionally ensures fuseOptions.sortFn is not ignored\n                choices.sort(sortByRank);\n            }\n            else if (config.shouldSort) {\n                choices.sort(config.sorter);\n            }\n            var choiceLimit = choices.length;\n            choiceLimit = !withinGroup && renderLimit > 0 && choiceLimit > renderLimit ? renderLimit : choiceLimit;\n            choiceLimit--;\n            choices.every(function (choice, index) {\n                // choiceEl being empty signals the contents has probably significantly changed\n                var dropdownItem = choice.choiceEl ||\n                    _this._templates.choice(config, choice, config.itemSelectText, showLabel && choice.group ? choice.group.label : undefined);\n                choice.choiceEl = dropdownItem;\n                fragment.appendChild(dropdownItem);\n                if (isSearching || !choice.selected) {\n                    selectableChoices = true;\n                }\n                else if (!highlightedEl) {\n                    highlightedEl = dropdownItem;\n                }\n                return index < choiceLimit;\n            });\n        };\n        if (activeChoices.length) {\n            if (config.resetScrollPosition) {\n                requestAnimationFrame(function () { return _this.choiceList.scrollToTop(); });\n            }\n            if (!this._hasNonChoicePlaceholder && !isSearching && this._isSelectOneElement) {\n                // If we have a placeholder choice along with groups\n                renderChoices(activeChoices.filter(function (choice) { return choice.placeholder && !choice.group; }), false);\n            }\n            // If we have grouped options\n            if (activeGroups.length && !isSearching) {\n                if (config.shouldSort) {\n                    activeGroups.sort(config.sorter);\n                }\n                // render Choices without group first, regardless of sort, otherwise they won't be distinguishable\n                // from the last group\n                renderChoices(activeChoices.filter(function (choice) { return !choice.placeholder && !choice.group; }), false);\n                activeGroups.forEach(function (group) {\n                    var groupChoices = renderableChoices(group.choices);\n                    if (groupChoices.length) {\n                        if (group.label) {\n                            var dropdownGroup = group.groupEl || _this._templates.choiceGroup(_this.config, group);\n                            group.groupEl = dropdownGroup;\n                            dropdownGroup.remove();\n                            fragment.appendChild(dropdownGroup);\n                        }\n                        renderChoices(groupChoices, true);\n                    }\n                });\n            }\n            else {\n                renderChoices(renderableChoices(activeChoices), false);\n            }\n        }\n        if (!selectableChoices && (isSearching || !fragment.children.length || !config.renderSelectedChoices)) {\n            if (!this._notice) {\n                this._notice = {\n                    text: resolveStringFunction(isSearching ? config.noResultsText : config.noChoicesText),\n                    type: isSearching ? NoticeTypes.noResults : NoticeTypes.noChoices,\n                };\n            }\n            fragment.replaceChildren('');\n        }\n        this._renderNotice(fragment);\n        this.choiceList.element.replaceChildren(fragment);\n        this._highlightChoice(highlightedEl);\n    };\n    Choices.prototype._renderItems = function () {\n        var _this = this;\n        var items = this._store.items || [];\n        var itemList = this.itemList.element;\n        var config = this.config;\n        var fragment = document.createDocumentFragment();\n        var itemFromList = function (item) {\n            return itemList.querySelector(\"[data-item][data-id=\\\"\".concat(item.id, \"\\\"]\"));\n        };\n        var addItemToFragment = function (item) {\n            var el = item.itemEl;\n            if (el && el.parentElement) {\n                return;\n            }\n            el = itemFromList(item) || _this._templates.item(config, item, config.removeItemButton);\n            item.itemEl = el;\n            fragment.appendChild(el);\n        };\n        // new items\n        items.forEach(addItemToFragment);\n        var addedItems = !!fragment.childNodes.length;\n        if (this._isSelectOneElement) {\n            var existingItems = itemList.children.length;\n            if (addedItems || existingItems > 1) {\n                var placeholder = itemList.querySelector(getClassNamesSelector(config.classNames.placeholder));\n                if (placeholder) {\n                    placeholder.remove();\n                }\n            }\n            else if (!addedItems && !existingItems && this._placeholderValue) {\n                addedItems = true;\n                addItemToFragment(mapInputToChoice({\n                    selected: true,\n                    value: '',\n                    label: this._placeholderValue,\n                    placeholder: true,\n                }, false));\n            }\n        }\n        if (addedItems) {\n            itemList.append(fragment);\n            if (config.shouldSortItems && !this._isSelectOneElement) {\n                items.sort(config.sorter);\n                // push sorting into the DOM\n                items.forEach(function (item) {\n                    var el = itemFromList(item);\n                    if (el) {\n                        el.remove();\n                        fragment.append(el);\n                    }\n                });\n                itemList.append(fragment);\n            }\n        }\n        if (this._isTextElement) {\n            // Update the value of the hidden input\n            this.passedElement.value = items.map(function (_a) {\n                var value = _a.value;\n                return value;\n            }).join(config.delimiter);\n        }\n    };\n    Choices.prototype._displayNotice = function (text, type, openDropdown) {\n        if (openDropdown === void 0) { openDropdown = true; }\n        var oldNotice = this._notice;\n        if (oldNotice &&\n            ((oldNotice.type === type && oldNotice.text === text) ||\n                (oldNotice.type === NoticeTypes.addChoice &&\n                    (type === NoticeTypes.noResults || type === NoticeTypes.noChoices)))) {\n            if (openDropdown) {\n                this.showDropdown(true);\n            }\n            return;\n        }\n        this._clearNotice();\n        this._notice = text\n            ? {\n                text: text,\n                type: type,\n            }\n            : undefined;\n        this._renderNotice();\n        if (openDropdown && text) {\n            this.showDropdown(true);\n        }\n    };\n    Choices.prototype._clearNotice = function () {\n        if (!this._notice) {\n            return;\n        }\n        var noticeElement = this.choiceList.element.querySelector(getClassNamesSelector(this.config.classNames.notice));\n        if (noticeElement) {\n            noticeElement.remove();\n        }\n        this._notice = undefined;\n    };\n    Choices.prototype._renderNotice = function (fragment) {\n        var noticeConf = this._notice;\n        if (noticeConf) {\n            var notice = this._templates.notice(this.config, noticeConf.text, noticeConf.type);\n            if (fragment) {\n                fragment.append(notice);\n            }\n            else {\n                this.choiceList.prepend(notice);\n            }\n        }\n    };\n    /**\n     * @deprecated Use utils.getChoiceForOutput\n     */\n    // eslint-disable-next-line class-methods-use-this\n    Choices.prototype._getChoiceForOutput = function (choice, keyCode) {\n        return getChoiceForOutput(choice, keyCode);\n    };\n    Choices.prototype._triggerChange = function (value) {\n        if (value === undefined || value === null) {\n            return;\n        }\n        this.passedElement.triggerEvent(EventType.change, {\n            value: value,\n        });\n    };\n    Choices.prototype._handleButtonAction = function (element) {\n        var _this = this;\n        var items = this._store.items;\n        if (!items.length || !this.config.removeItems || !this.config.removeItemButton) {\n            return;\n        }\n        var id = element && parseDataSetId(element.closest('[data-id]'));\n        var itemToRemove = id && items.find(function (item) { return item.id === id; });\n        if (!itemToRemove) {\n            return;\n        }\n        this._store.withTxn(function () {\n            // Remove item associated with button\n            _this._removeItem(itemToRemove);\n            _this._triggerChange(itemToRemove.value);\n            if (_this._isSelectOneElement && !_this._hasNonChoicePlaceholder) {\n                var placeholderChoice = (_this.config.shouldSort ? _this._store.choices.reverse() : _this._store.choices).find(function (choice) { return choice.placeholder; });\n                if (placeholderChoice) {\n                    _this._addItem(placeholderChoice);\n                    _this.unhighlightAll();\n                    if (placeholderChoice.value) {\n                        _this._triggerChange(placeholderChoice.value);\n                    }\n                }\n            }\n        });\n    };\n    Choices.prototype._handleItemAction = function (element, hasShiftKey) {\n        var _this = this;\n        if (hasShiftKey === void 0) { hasShiftKey = false; }\n        var items = this._store.items;\n        if (!items.length || !this.config.removeItems || this._isSelectOneElement) {\n            return;\n        }\n        var id = parseDataSetId(element);\n        if (!id) {\n            return;\n        }\n        // We only want to select one item with a click\n        // so we deselect any items that aren't the target\n        // unless shift is being pressed\n        items.forEach(function (item) {\n            if (item.id === id && !item.highlighted) {\n                _this.highlightItem(item);\n            }\n            else if (!hasShiftKey && item.highlighted) {\n                _this.unhighlightItem(item);\n            }\n        });\n        // Focus input as without focus, a user cannot do anything with a\n        // highlighted item\n        this.input.focus();\n    };\n    Choices.prototype._handleChoiceAction = function (element) {\n        var _this = this;\n        // If we are clicking on an option\n        var id = parseDataSetId(element);\n        var choice = id && this._store.getChoiceById(id);\n        if (!choice || choice.disabled) {\n            return false;\n        }\n        var hasActiveDropdown = this.dropdown.isActive;\n        if (!choice.selected) {\n            if (!this._canAddItems()) {\n                return true; // causes _onEnterKey to early out\n            }\n            this._store.withTxn(function () {\n                _this._addItem(choice, true, true);\n                _this.clearInput();\n                _this.unhighlightAll();\n            });\n            this._triggerChange(choice.value);\n        }\n        // We want to close the dropdown if we are dealing with a single select box\n        if (hasActiveDropdown && this.config.closeDropdownOnSelect) {\n            this.hideDropdown(true);\n            this.containerOuter.element.focus();\n        }\n        return true;\n    };\n    Choices.prototype._handleBackspace = function (items) {\n        var config = this.config;\n        if (!config.removeItems || !items.length) {\n            return;\n        }\n        var lastItem = items[items.length - 1];\n        var hasHighlightedItems = items.some(function (item) { return item.highlighted; });\n        // If editing the last item is allowed and there are not other selected items,\n        // we can edit the item value. Otherwise if we can remove items, remove all selected items\n        if (config.editItems && !hasHighlightedItems && lastItem) {\n            this.input.value = lastItem.value;\n            this.input.setWidth();\n            this._removeItem(lastItem);\n            this._triggerChange(lastItem.value);\n        }\n        else {\n            if (!hasHighlightedItems) {\n                // Highlight last item if none already highlighted\n                this.highlightItem(lastItem, false);\n            }\n            this.removeHighlightedItems(true);\n        }\n    };\n    Choices.prototype._loadChoices = function () {\n        var _a;\n        var _this = this;\n        var config = this.config;\n        if (this._isTextElement) {\n            // Assign preset items from passed object first\n            this._presetChoices = config.items.map(function (e) { return mapInputToChoice(e, false); });\n            // Add any values passed from attribute\n            if (this.passedElement.value) {\n                var elementItems = this.passedElement.value\n                    .split(config.delimiter)\n                    .map(function (e) { return mapInputToChoice(e, false, _this.config.allowHtmlUserInput); });\n                this._presetChoices = this._presetChoices.concat(elementItems);\n            }\n            this._presetChoices.forEach(function (choice) {\n                choice.selected = true;\n            });\n        }\n        else if (this._isSelectElement) {\n            // Assign preset choices from passed object\n            this._presetChoices = config.choices.map(function (e) { return mapInputToChoice(e, true); });\n            // Create array of choices from option elements\n            var choicesFromOptions = this.passedElement.optionsAsChoices();\n            if (choicesFromOptions) {\n                (_a = this._presetChoices).push.apply(_a, choicesFromOptions);\n            }\n        }\n    };\n    Choices.prototype._handleLoadingState = function (setLoading) {\n        if (setLoading === void 0) { setLoading = true; }\n        var el = this.itemList.element;\n        if (setLoading) {\n            this.disable();\n            this.containerOuter.addLoadingState();\n            if (this._isSelectOneElement) {\n                el.replaceChildren(this._templates.placeholder(this.config, this.config.loadingText));\n            }\n            else {\n                this.input.placeholder = this.config.loadingText;\n            }\n        }\n        else {\n            this.enable();\n            this.containerOuter.removeLoadingState();\n            if (this._isSelectOneElement) {\n                el.replaceChildren('');\n                this._render();\n            }\n            else {\n                this.input.placeholder = this._placeholderValue || '';\n            }\n        }\n    };\n    Choices.prototype._handleSearch = function (value) {\n        if (!this.input.isFocussed) {\n            return;\n        }\n        // Check that we have a value to search and the input was an alphanumeric character\n        if (value !== null && typeof value !== 'undefined' && value.length >= this.config.searchFloor) {\n            var resultCount = this.config.searchChoices ? this._searchChoices(value) : 0;\n            if (resultCount !== null) {\n                // Trigger search event\n                this.passedElement.triggerEvent(EventType.search, {\n                    value: value,\n                    resultCount: resultCount,\n                });\n            }\n        }\n        else if (this._store.choices.some(function (option) { return !option.active; })) {\n            this._stopSearch();\n        }\n    };\n    Choices.prototype._canAddItems = function () {\n        var config = this.config;\n        var maxItemCount = config.maxItemCount, maxItemText = config.maxItemText;\n        if (!config.singleModeForMultiSelect && maxItemCount > 0 && maxItemCount <= this._store.items.length) {\n            this.choiceList.element.replaceChildren('');\n            this._notice = undefined;\n            this._displayNotice(typeof maxItemText === 'function' ? maxItemText(maxItemCount) : maxItemText, NoticeTypes.addChoice);\n            return false;\n        }\n        if (this._notice && this._notice.type === NoticeTypes.addChoice) {\n            this._clearNotice();\n        }\n        return true;\n    };\n    Choices.prototype._canCreateItem = function (value) {\n        var config = this.config;\n        var canAddItem = true;\n        var notice = '';\n        if (canAddItem && typeof config.addItemFilter === 'function' && !config.addItemFilter(value)) {\n            canAddItem = false;\n            notice = resolveNoticeFunction(config.customAddItemText, value, undefined);\n        }\n        if (canAddItem) {\n            var foundChoice = this._store.choices.find(function (choice) { return config.valueComparer(choice.value, value); });\n            if (foundChoice) {\n                if (this._isSelectElement) {\n                    // for exact matches, do not prompt to add it as a custom choice\n                    this._displayNotice('', NoticeTypes.addChoice);\n                    return false;\n                }\n                if (!config.duplicateItemsAllowed) {\n                    canAddItem = false;\n                    notice = resolveNoticeFunction(config.uniqueItemText, value, undefined);\n                }\n            }\n        }\n        if (canAddItem) {\n            notice = resolveNoticeFunction(config.addItemText, value, undefined);\n        }\n        if (notice) {\n            this._displayNotice(notice, NoticeTypes.addChoice);\n        }\n        return canAddItem;\n    };\n    Choices.prototype._searchChoices = function (value) {\n        var newValue = value.trim().replace(/\\s{2,}/, ' ');\n        // signal input didn't change search\n        if (!newValue.length || newValue === this._currentValue) {\n            return null;\n        }\n        var searcher = this._searcher;\n        if (searcher.isEmptyIndex()) {\n            searcher.index(this._store.searchableChoices);\n        }\n        // If new value matches the desired length and is not the same as the current value with a space\n        var results = searcher.search(newValue);\n        this._currentValue = newValue;\n        this._highlightPosition = 0;\n        this._isSearching = true;\n        var notice = this._notice;\n        var noticeType = notice && notice.type;\n        if (noticeType !== NoticeTypes.addChoice) {\n            if (!results.length) {\n                this._displayNotice(resolveStringFunction(this.config.noResultsText), NoticeTypes.noResults);\n            }\n            else {\n                this._clearNotice();\n            }\n        }\n        this._store.dispatch(filterChoices(results));\n        return results.length;\n    };\n    Choices.prototype._stopSearch = function () {\n        if (this._isSearching) {\n            this._currentValue = '';\n            this._isSearching = false;\n            this._clearNotice();\n            this._store.dispatch(activateChoices(true));\n            this.passedElement.triggerEvent(EventType.search, {\n                value: '',\n                resultCount: 0,\n            });\n        }\n    };\n    Choices.prototype._addEventListeners = function () {\n        var documentElement = this._docRoot;\n        var outerElement = this.containerOuter.element;\n        var inputElement = this.input.element;\n        var passedElement = this.passedElement.element;\n        // capture events - can cancel event processing or propagation\n        documentElement.addEventListener('touchend', this._onTouchEnd, true);\n        outerElement.addEventListener('keydown', this._onKeyDown, true);\n        outerElement.addEventListener('mousedown', this._onMouseDown, true);\n        // passive events - doesn't call `preventDefault` or `stopPropagation`\n        documentElement.addEventListener('click', this._onClick, { passive: true });\n        documentElement.addEventListener('touchmove', this._onTouchMove, {\n            passive: true,\n        });\n        this.dropdown.element.addEventListener('mouseover', this._onMouseOver, {\n            passive: true,\n        });\n        if (this._isSelectOneElement) {\n            outerElement.addEventListener('focus', this._onFocus, {\n                passive: true,\n            });\n            outerElement.addEventListener('blur', this._onBlur, {\n                passive: true,\n            });\n        }\n        inputElement.addEventListener('keyup', this._onKeyUp, {\n            passive: true,\n        });\n        inputElement.addEventListener('input', this._onInput, {\n            passive: true,\n        });\n        inputElement.addEventListener('focus', this._onFocus, {\n            passive: true,\n        });\n        inputElement.addEventListener('blur', this._onBlur, {\n            passive: true,\n        });\n        if (inputElement.form) {\n            inputElement.form.addEventListener('reset', this._onFormReset, {\n                passive: true,\n            });\n        }\n        if (passedElement.hasAttribute('required')) {\n            passedElement.addEventListener('change', this._onChange, {\n                passive: true,\n            });\n            passedElement.addEventListener('invalid', this._onInvalid, {\n                passive: true,\n            });\n        }\n        this.input.addEventListeners();\n    };\n    Choices.prototype._removeEventListeners = function () {\n        var documentElement = this._docRoot;\n        var outerElement = this.containerOuter.element;\n        var inputElement = this.input.element;\n        var passedElement = this.passedElement.element;\n        documentElement.removeEventListener('touchend', this._onTouchEnd, true);\n        outerElement.removeEventListener('keydown', this._onKeyDown, true);\n        outerElement.removeEventListener('mousedown', this._onMouseDown, true);\n        documentElement.removeEventListener('click', this._onClick);\n        documentElement.removeEventListener('touchmove', this._onTouchMove);\n        this.dropdown.element.removeEventListener('mouseover', this._onMouseOver);\n        if (this._isSelectOneElement) {\n            outerElement.removeEventListener('focus', this._onFocus);\n            outerElement.removeEventListener('blur', this._onBlur);\n        }\n        inputElement.removeEventListener('keyup', this._onKeyUp);\n        inputElement.removeEventListener('input', this._onInput);\n        inputElement.removeEventListener('focus', this._onFocus);\n        inputElement.removeEventListener('blur', this._onBlur);\n        if (inputElement.form) {\n            inputElement.form.removeEventListener('reset', this._onFormReset);\n        }\n        if (passedElement.hasAttribute('required')) {\n            passedElement.removeEventListener('change', this._onChange);\n            passedElement.removeEventListener('invalid', this._onInvalid);\n        }\n        this.input.removeEventListeners();\n    };\n    Choices.prototype._onKeyDown = function (event) {\n        var keyCode = event.keyCode;\n        var hasActiveDropdown = this.dropdown.isActive;\n        /*\n        See:\n        https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key\n        https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values\n        https://en.wikipedia.org/wiki/UTF-16#Code_points_from_U+010000_to_U+10FFFF - UTF-16 surrogate pairs\n        https://stackoverflow.com/a/70866532 - \"Unidentified\" for mobile\n        http://www.unicode.org/versions/Unicode5.2.0/ch16.pdf#G19635 - U+FFFF is reserved (Section 16.7)\n    \n        Logic: when a key event is sent, `event.key` represents its printable value _or_ one\n        of a large list of special values indicating meta keys/functionality. In addition,\n        key events for compose functionality contain a value of `Dead` when mid-composition.\n    \n        I can't quite verify it, but non-English IMEs may also be able to generate key codes\n        for code points in the surrogate-pair range, which could potentially be seen as having\n        key.length > 1. Since `Fn` is one of the special keys, we can't distinguish by that\n        alone.\n    \n        Here, key.length === 1 means we know for sure the input was printable and not a special\n        `key` value. When the length is greater than 1, it could be either a printable surrogate\n        pair or a special `key` value. We can tell the difference by checking if the _character\n        code_ value (not code point!) is in the \"surrogate pair\" range or not.\n    \n        We don't use .codePointAt because an invalid code point would return 65535, which wouldn't\n        pass the >= 0x10000 check we would otherwise use.\n    \n        > ...The Unicode Standard sets aside 66 noncharacter code points. The last two code points\n        > of each plane are noncharacters: U+FFFE and U+FFFF on the BMP...\n        */\n        var wasPrintableChar = event.key.length === 1 ||\n            (event.key.length === 2 && event.key.charCodeAt(0) >= 0xd800) ||\n            event.key === 'Unidentified';\n        /*\n          We do not show the dropdown if focusing out with esc or navigating through input fields.\n          An activated search can still be opened with any other key.\n         */\n        if (!this._isTextElement &&\n            !hasActiveDropdown &&\n            keyCode !== KeyCodeMap.ESC_KEY &&\n            keyCode !== KeyCodeMap.TAB_KEY &&\n            keyCode !== KeyCodeMap.SHIFT_KEY) {\n            this.showDropdown();\n            if (!this.input.isFocussed && wasPrintableChar) {\n                /*\n                  We update the input value with the pressed key as\n                  the input was not focussed at the time of key press\n                  therefore does not have the value of the key.\n                */\n                this.input.value += event.key;\n                // browsers interpret a space as pagedown\n                if (event.key === ' ') {\n                    event.preventDefault();\n                }\n            }\n        }\n        switch (keyCode) {\n            case KeyCodeMap.A_KEY:\n                return this._onSelectKey(event, this.itemList.element.hasChildNodes());\n            case KeyCodeMap.ENTER_KEY:\n                return this._onEnterKey(event, hasActiveDropdown);\n            case KeyCodeMap.ESC_KEY:\n                return this._onEscapeKey(event, hasActiveDropdown);\n            case KeyCodeMap.UP_KEY:\n            case KeyCodeMap.PAGE_UP_KEY:\n            case KeyCodeMap.DOWN_KEY:\n            case KeyCodeMap.PAGE_DOWN_KEY:\n                return this._onDirectionKey(event, hasActiveDropdown);\n            case KeyCodeMap.DELETE_KEY:\n            case KeyCodeMap.BACK_KEY:\n                return this._onDeleteKey(event, this._store.items, this.input.isFocussed);\n        }\n    };\n    Choices.prototype._onKeyUp = function ( /* event: KeyboardEvent */) {\n        this._canSearch = this.config.searchEnabled;\n    };\n    Choices.prototype._onInput = function ( /* event: InputEvent */) {\n        var value = this.input.value;\n        if (!value) {\n            if (this._isTextElement) {\n                this.hideDropdown(true);\n            }\n            else {\n                this._stopSearch();\n            }\n            return;\n        }\n        if (!this._canAddItems()) {\n            return;\n        }\n        if (this._canSearch) {\n            // do the search even if the entered text can not be added\n            this._handleSearch(value);\n        }\n        if (!this._canAddUserChoices) {\n            return;\n        }\n        // determine if a notice needs to be displayed for why a search result can't be added\n        this._canCreateItem(value);\n        if (this._isSelectElement) {\n            this._highlightPosition = 0; // reset to select the notice and/or exact match\n            this._highlightChoice();\n        }\n    };\n    Choices.prototype._onSelectKey = function (event, hasItems) {\n        // If CTRL + A or CMD + A have been pressed and there are items to select\n        if ((event.ctrlKey || event.metaKey) && hasItems) {\n            this._canSearch = false;\n            var shouldHightlightAll = this.config.removeItems && !this.input.value && this.input.element === document.activeElement;\n            if (shouldHightlightAll) {\n                this.highlightAll();\n            }\n        }\n    };\n    Choices.prototype._onEnterKey = function (event, hasActiveDropdown) {\n        var _this = this;\n        var value = this.input.value;\n        var target = event.target;\n        event.preventDefault();\n        if (target && target.hasAttribute('data-button')) {\n            this._handleButtonAction(target);\n            return;\n        }\n        if (!hasActiveDropdown) {\n            if (this._isSelectElement || this._notice) {\n                this.showDropdown();\n            }\n            return;\n        }\n        var highlightedChoice = this.dropdown.element.querySelector(getClassNamesSelector(this.config.classNames.highlightedState));\n        if (highlightedChoice && this._handleChoiceAction(highlightedChoice)) {\n            return;\n        }\n        if (!target || !value) {\n            this.hideDropdown(true);\n            return;\n        }\n        if (!this._canAddItems()) {\n            return;\n        }\n        var addedItem = false;\n        this._store.withTxn(function () {\n            addedItem = _this._findAndSelectChoiceByValue(value, true);\n            if (!addedItem) {\n                if (!_this._canAddUserChoices) {\n                    return;\n                }\n                if (!_this._canCreateItem(value)) {\n                    return;\n                }\n                _this._addChoice(mapInputToChoice(value, false, _this.config.allowHtmlUserInput), true, true);\n                addedItem = true;\n            }\n            _this.clearInput();\n            _this.unhighlightAll();\n        });\n        if (!addedItem) {\n            return;\n        }\n        this._triggerChange(value);\n        if (this.config.closeDropdownOnSelect) {\n            this.hideDropdown(true);\n        }\n    };\n    Choices.prototype._onEscapeKey = function (event, hasActiveDropdown) {\n        if (hasActiveDropdown) {\n            event.stopPropagation();\n            this.hideDropdown(true);\n            this._stopSearch();\n            this.containerOuter.element.focus();\n        }\n    };\n    Choices.prototype._onDirectionKey = function (event, hasActiveDropdown) {\n        var keyCode = event.keyCode;\n        // If up or down key is pressed, traverse through options\n        if (hasActiveDropdown || this._isSelectOneElement) {\n            this.showDropdown();\n            this._canSearch = false;\n            var directionInt = keyCode === KeyCodeMap.DOWN_KEY || keyCode === KeyCodeMap.PAGE_DOWN_KEY ? 1 : -1;\n            var skipKey = event.metaKey || keyCode === KeyCodeMap.PAGE_DOWN_KEY || keyCode === KeyCodeMap.PAGE_UP_KEY;\n            var nextEl = void 0;\n            if (skipKey) {\n                if (directionInt > 0) {\n                    nextEl = this.dropdown.element.querySelector(\"\".concat(selectableChoiceIdentifier, \":last-of-type\"));\n                }\n                else {\n                    nextEl = this.dropdown.element.querySelector(selectableChoiceIdentifier);\n                }\n            }\n            else {\n                var currentEl = this.dropdown.element.querySelector(getClassNamesSelector(this.config.classNames.highlightedState));\n                if (currentEl) {\n                    nextEl = getAdjacentEl(currentEl, selectableChoiceIdentifier, directionInt);\n                }\n                else {\n                    nextEl = this.dropdown.element.querySelector(selectableChoiceIdentifier);\n                }\n            }\n            if (nextEl) {\n                // We prevent default to stop the cursor moving\n                // when pressing the arrow\n                if (!isScrolledIntoView(nextEl, this.choiceList.element, directionInt)) {\n                    this.choiceList.scrollToChildElement(nextEl, directionInt);\n                }\n                this._highlightChoice(nextEl);\n            }\n            // Prevent default to maintain cursor position whilst\n            // traversing dropdown options\n            event.preventDefault();\n        }\n    };\n    Choices.prototype._onDeleteKey = function (event, items, hasFocusedInput) {\n        // If backspace or delete key is pressed and the input has no value\n        if (!this._isSelectOneElement && !event.target.value && hasFocusedInput) {\n            this._handleBackspace(items);\n            event.preventDefault();\n        }\n    };\n    Choices.prototype._onTouchMove = function () {\n        if (this._wasTap) {\n            this._wasTap = false;\n        }\n    };\n    Choices.prototype._onTouchEnd = function (event) {\n        var target = (event || event.touches[0]).target;\n        var touchWasWithinContainer = this._wasTap && this.containerOuter.element.contains(target);\n        if (touchWasWithinContainer) {\n            var containerWasExactTarget = target === this.containerOuter.element || target === this.containerInner.element;\n            if (containerWasExactTarget) {\n                if (this._isTextElement) {\n                    this.input.focus();\n                }\n                else if (this._isSelectMultipleElement) {\n                    this.showDropdown();\n                }\n            }\n            // Prevents focus event firing\n            event.stopPropagation();\n        }\n        this._wasTap = true;\n    };\n    /**\n     * Handles mousedown event in capture mode for containetOuter.element\n     */\n    Choices.prototype._onMouseDown = function (event) {\n        var target = event.target;\n        if (!(target instanceof Element)) {\n            return;\n        }\n        // If we have our mouse down on the scrollbar and are on IE11...\n        if (IS_IE11 && this.choiceList.element.contains(target)) {\n            // check if click was on a scrollbar area\n            var firstChoice = this.choiceList.element.firstElementChild;\n            this._isScrollingOnIe =\n                this._direction === 'ltr' ? event.offsetX >= firstChoice.offsetWidth : event.offsetX < firstChoice.offsetLeft;\n        }\n        if (target === this.input.element) {\n            return;\n        }\n        var item = target.closest('[data-button],[data-item],[data-choice]');\n        if (item instanceof HTMLElement) {\n            if ('button' in item.dataset) {\n                this._handleButtonAction(item);\n            }\n            else if ('item' in item.dataset) {\n                this._handleItemAction(item, event.shiftKey);\n            }\n            else if ('choice' in item.dataset) {\n                this._handleChoiceAction(item);\n            }\n        }\n        event.preventDefault();\n    };\n    /**\n     * Handles mouseover event over this.dropdown\n     * @param {MouseEvent} event\n     */\n    Choices.prototype._onMouseOver = function (_a) {\n        var target = _a.target;\n        if (target instanceof HTMLElement && 'choice' in target.dataset) {\n            this._highlightChoice(target);\n        }\n    };\n    Choices.prototype._onClick = function (_a) {\n        var target = _a.target;\n        var containerOuter = this.containerOuter;\n        var clickWasWithinContainer = containerOuter.element.contains(target);\n        if (clickWasWithinContainer) {\n            if (!this.dropdown.isActive && !containerOuter.isDisabled) {\n                if (this._isTextElement) {\n                    if (document.activeElement !== this.input.element) {\n                        this.input.focus();\n                    }\n                }\n                else {\n                    this.showDropdown();\n                    containerOuter.element.focus();\n                }\n            }\n            else if (this._isSelectOneElement &&\n                target !== this.input.element &&\n                !this.dropdown.element.contains(target)) {\n                this.hideDropdown();\n            }\n        }\n        else {\n            containerOuter.removeFocusState();\n            this.hideDropdown(true);\n            this.unhighlightAll();\n        }\n    };\n    Choices.prototype._onFocus = function (_a) {\n        var target = _a.target;\n        var containerOuter = this.containerOuter;\n        var focusWasWithinContainer = target && containerOuter.element.contains(target);\n        if (!focusWasWithinContainer) {\n            return;\n        }\n        var targetIsInput = target === this.input.element;\n        if (this._isTextElement) {\n            if (targetIsInput) {\n                containerOuter.addFocusState();\n            }\n        }\n        else if (this._isSelectMultipleElement) {\n            if (targetIsInput) {\n                this.showDropdown(true);\n                // If element is a select box, the focused element is the container and the dropdown\n                // isn't already open, focus and show dropdown\n                containerOuter.addFocusState();\n            }\n        }\n        else {\n            containerOuter.addFocusState();\n            if (targetIsInput) {\n                this.showDropdown(true);\n            }\n        }\n    };\n    Choices.prototype._onBlur = function (_a) {\n        var target = _a.target;\n        var containerOuter = this.containerOuter;\n        var blurWasWithinContainer = target && containerOuter.element.contains(target);\n        if (blurWasWithinContainer && !this._isScrollingOnIe) {\n            if (target === this.input.element) {\n                containerOuter.removeFocusState();\n                this.hideDropdown(true);\n                if (this._isTextElement || this._isSelectMultipleElement) {\n                    this.unhighlightAll();\n                }\n            }\n            else if (target === this.containerOuter.element) {\n                // Remove the focus state when the past outerContainer was the target\n                containerOuter.removeFocusState();\n                // Also close the dropdown if search is disabled\n                if (!this.config.searchEnabled) {\n                    this.hideDropdown(true);\n                }\n            }\n        }\n        else {\n            // On IE11, clicking the scollbar blurs our input and thus\n            // closes the dropdown. To stop this, we refocus our input\n            // if we know we are on IE *and* are scrolling.\n            this._isScrollingOnIe = false;\n            this.input.element.focus();\n        }\n    };\n    Choices.prototype._onFormReset = function () {\n        var _this = this;\n        this._store.withTxn(function () {\n            _this.clearInput();\n            _this.hideDropdown();\n            _this.refresh(false, false, true);\n            if (_this._initialItems.length) {\n                _this.setChoiceByValue(_this._initialItems);\n            }\n        });\n    };\n    Choices.prototype._onChange = function (event) {\n        if (!event.target.checkValidity()) {\n            return;\n        }\n        this.containerOuter.removeInvalidState();\n    };\n    Choices.prototype._onInvalid = function () {\n        this.containerOuter.addInvalidState();\n    };\n    /**\n     * Removes any highlighted choice options\n     */\n    Choices.prototype._removeHighlightedChoices = function () {\n        var highlightedState = this.config.classNames.highlightedState;\n        var highlightedChoices = Array.from(this.dropdown.element.querySelectorAll(getClassNamesSelector(highlightedState)));\n        // Remove any highlighted choices\n        highlightedChoices.forEach(function (choice) {\n            removeClassesFromElement(choice, highlightedState);\n            choice.setAttribute('aria-selected', 'false');\n        });\n    };\n    Choices.prototype._highlightChoice = function (el) {\n        if (el === void 0) { el = null; }\n        var choices = Array.from(this.dropdown.element.querySelectorAll(selectableChoiceIdentifier));\n        if (!choices.length) {\n            return;\n        }\n        var passedEl = el;\n        var highlightedState = this.config.classNames.highlightedState;\n        this._removeHighlightedChoices();\n        if (passedEl) {\n            this._highlightPosition = choices.indexOf(passedEl);\n        }\n        else {\n            // Highlight choice based on last known highlight location\n            if (choices.length > this._highlightPosition) {\n                // If we have an option to highlight\n                passedEl = choices[this._highlightPosition];\n            }\n            else {\n                // Otherwise highlight the option before\n                passedEl = choices[choices.length - 1];\n            }\n            if (!passedEl) {\n                passedEl = choices[0];\n            }\n        }\n        addClassesToElement(passedEl, highlightedState);\n        passedEl.setAttribute('aria-selected', 'true');\n        this.passedElement.triggerEvent(EventType.highlightChoice, {\n            el: passedEl,\n        });\n        if (this.dropdown.isActive) {\n            // IE11 ignores aria-label and blocks virtual keyboard\n            // if aria-activedescendant is set without a dropdown\n            this.input.setActiveDescendant(passedEl.id);\n            this.containerOuter.setActiveDescendant(passedEl.id);\n        }\n    };\n    Choices.prototype._addItem = function (item, withEvents, userTriggered) {\n        if (withEvents === void 0) { withEvents = true; }\n        if (userTriggered === void 0) { userTriggered = false; }\n        if (!item.id) {\n            throw new TypeError('item.id must be set before _addItem is called for a choice/item');\n        }\n        if (this.config.singleModeForMultiSelect || this._isSelectOneElement) {\n            this.removeActiveItems(item.id);\n        }\n        this._store.dispatch(addItem(item));\n        if (withEvents) {\n            var eventChoice = getChoiceForOutput(item);\n            this.passedElement.triggerEvent(EventType.addItem, eventChoice);\n            if (userTriggered) {\n                this.passedElement.triggerEvent(EventType.choice, eventChoice);\n            }\n        }\n    };\n    Choices.prototype._removeItem = function (item) {\n        if (!item.id) {\n            return;\n        }\n        this._store.dispatch(removeItem$1(item));\n        var notice = this._notice;\n        if (notice && notice.type === NoticeTypes.noChoices) {\n            this._clearNotice();\n        }\n        this.passedElement.triggerEvent(EventType.removeItem, getChoiceForOutput(item));\n    };\n    Choices.prototype._addChoice = function (choice, withEvents, userTriggered) {\n        if (withEvents === void 0) { withEvents = true; }\n        if (userTriggered === void 0) { userTriggered = false; }\n        if (choice.id) {\n            throw new TypeError('Can not re-add a choice which has already been added');\n        }\n        var config = this.config;\n        if (!config.duplicateItemsAllowed && this._store.choices.find(function (c) { return config.valueComparer(c.value, choice.value); })) {\n            return;\n        }\n        // Generate unique id, in-place update is required so chaining _addItem works as expected\n        this._lastAddedChoiceId++;\n        choice.id = this._lastAddedChoiceId;\n        choice.elementId = \"\".concat(this._baseId, \"-\").concat(this._idNames.itemChoice, \"-\").concat(choice.id);\n        var prependValue = config.prependValue, appendValue = config.appendValue;\n        if (prependValue) {\n            choice.value = prependValue + choice.value;\n        }\n        if (appendValue) {\n            choice.value += appendValue.toString();\n        }\n        if ((prependValue || appendValue) && choice.element) {\n            choice.element.value = choice.value;\n        }\n        this._clearNotice();\n        this._store.dispatch(addChoice(choice));\n        if (choice.selected) {\n            this._addItem(choice, withEvents, userTriggered);\n        }\n    };\n    Choices.prototype._addGroup = function (group, withEvents) {\n        var _this = this;\n        if (withEvents === void 0) { withEvents = true; }\n        if (group.id) {\n            throw new TypeError('Can not re-add a group which has already been added');\n        }\n        this._store.dispatch(addGroup(group));\n        if (!group.choices) {\n            return;\n        }\n        // add unique id for the group(s), and do not store the full list of choices in this group\n        this._lastAddedGroupId++;\n        group.id = this._lastAddedGroupId;\n        group.choices.forEach(function (item) {\n            item.group = group;\n            if (group.disabled) {\n                item.disabled = true;\n            }\n            _this._addChoice(item, withEvents);\n        });\n    };\n    Choices.prototype._createTemplates = function () {\n        var _this = this;\n        var callbackOnCreateTemplates = this.config.callbackOnCreateTemplates;\n        var userTemplates = {};\n        if (typeof callbackOnCreateTemplates === 'function') {\n            userTemplates = callbackOnCreateTemplates.call(this, strToEl, escapeForTemplate, getClassNames);\n        }\n        var templating = {};\n        Object.keys(this._templates).forEach(function (name) {\n            if (name in userTemplates) {\n                templating[name] = userTemplates[name].bind(_this);\n            }\n            else {\n                templating[name] = _this._templates[name].bind(_this);\n            }\n        });\n        this._templates = templating;\n    };\n    Choices.prototype._createElements = function () {\n        var templating = this._templates;\n        var _a = this, config = _a.config, isSelectOneElement = _a._isSelectOneElement;\n        var position = config.position, classNames = config.classNames;\n        var elementType = this._elementType;\n        this.containerOuter = new Container({\n            element: templating.containerOuter(config, this._direction, this._isSelectElement, isSelectOneElement, config.searchEnabled, elementType, config.labelId),\n            classNames: classNames,\n            type: elementType,\n            position: position,\n        });\n        this.containerInner = new Container({\n            element: templating.containerInner(config),\n            classNames: classNames,\n            type: elementType,\n            position: position,\n        });\n        this.input = new Input({\n            element: templating.input(config, this._placeholderValue),\n            classNames: classNames,\n            type: elementType,\n            preventPaste: !config.paste,\n        });\n        this.choiceList = new List({\n            element: templating.choiceList(config, isSelectOneElement),\n        });\n        this.itemList = new List({\n            element: templating.itemList(config, isSelectOneElement),\n        });\n        this.dropdown = new Dropdown({\n            element: templating.dropdown(config),\n            classNames: classNames,\n            type: elementType,\n        });\n    };\n    Choices.prototype._createStructure = function () {\n        var _a = this, containerInner = _a.containerInner, containerOuter = _a.containerOuter, passedElement = _a.passedElement;\n        var dropdownElement = this.dropdown.element;\n        // Hide original element\n        passedElement.conceal();\n        // Wrap input in container preserving DOM ordering\n        containerInner.wrap(passedElement.element);\n        // Wrapper inner container with outer container\n        containerOuter.wrap(containerInner.element);\n        containerOuter.element.appendChild(containerInner.element);\n        containerOuter.element.appendChild(dropdownElement);\n        containerInner.element.appendChild(this.itemList.element);\n        dropdownElement.appendChild(this.choiceList.element);\n        if (this._isSelectOneElement) {\n            this.input.placeholder = this.config.searchPlaceholderValue || '';\n            if (this.config.searchEnabled) {\n                dropdownElement.insertBefore(this.input.element, dropdownElement.firstChild);\n            }\n        }\n        else {\n            if (!this._isSelectMultipleElement || this.config.searchEnabled) {\n                containerInner.element.appendChild(this.input.element);\n            }\n            if (this._placeholderValue) {\n                this.input.placeholder = this._placeholderValue;\n            }\n            this.input.setWidth();\n        }\n        this._highlightPosition = 0;\n        this._isSearching = false;\n    };\n    Choices.prototype._initStore = function () {\n        var _this = this;\n        this._store.subscribe(this._render).withTxn(function () {\n            _this._addPredefinedChoices(_this._presetChoices, _this._isSelectOneElement && !_this._hasNonChoicePlaceholder, false);\n        });\n        if (!this._store.choices.length || (this._isSelectOneElement && this._hasNonChoicePlaceholder)) {\n            this._render();\n        }\n    };\n    Choices.prototype._addPredefinedChoices = function (choices, selectFirstOption, withEvents) {\n        var _this = this;\n        if (selectFirstOption === void 0) { selectFirstOption = false; }\n        if (withEvents === void 0) { withEvents = true; }\n        if (selectFirstOption) {\n            /**\n             * If there is a selected choice already or the choice is not the first in\n             * the array, add each choice normally.\n             *\n             * Otherwise we pre-select the first enabled choice in the array (\"select-one\" only)\n             */\n            var noSelectedChoices = choices.findIndex(function (choice) { return choice.selected; }) === -1;\n            if (noSelectedChoices) {\n                choices.some(function (choice) {\n                    if (choice.disabled || 'choices' in choice) {\n                        return false;\n                    }\n                    choice.selected = true;\n                    return true;\n                });\n            }\n        }\n        choices.forEach(function (item) {\n            if ('choices' in item) {\n                if (_this._isSelectElement) {\n                    _this._addGroup(item, withEvents);\n                }\n            }\n            else {\n                _this._addChoice(item, withEvents);\n            }\n        });\n    };\n    Choices.prototype._findAndSelectChoiceByValue = function (value, userTriggered) {\n        var _this = this;\n        if (userTriggered === void 0) { userTriggered = false; }\n        // Check 'value' property exists and the choice isn't already selected\n        var foundChoice = this._store.choices.find(function (choice) { return _this.config.valueComparer(choice.value, value); });\n        if (foundChoice && !foundChoice.disabled && !foundChoice.selected) {\n            this._addItem(foundChoice, true, userTriggered);\n            return true;\n        }\n        return false;\n    };\n    Choices.prototype._generatePlaceholderValue = function () {\n        var config = this.config;\n        if (!config.placeholder) {\n            return null;\n        }\n        if (this._hasNonChoicePlaceholder) {\n            return config.placeholderValue;\n        }\n        if (this._isSelectElement) {\n            var placeholderOption = this.passedElement.placeholderOption;\n            return placeholderOption ? placeholderOption.text : null;\n        }\n        return null;\n    };\n    Choices.prototype._warnChoicesInitFailed = function (caller) {\n        if (this.config.silent) {\n            return;\n        }\n        if (!this.initialised) {\n            throw new TypeError(\"\".concat(caller, \" called on a non-initialised instance of Choices\"));\n        }\n        else if (!this.initialisedOK) {\n            throw new TypeError(\"\".concat(caller, \" called for an element which has multiple instances of Choices initialised on it\"));\n        }\n    };\n    Choices.version = '11.2.1';\n    return Choices;\n}());\n\nexport { Choices as default };\n"
  },
  {
    "path": "public/assets/scripts/choices.search-kmp.js",
    "content": "/*! choices.js v11.2.1 | © 2026 Josh Johnson | https://github.com/Choices-js/Choices#readme */\n\n(function (global, factory) {\n    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :\n    typeof define === 'function' && define.amd ? define(factory) :\n    (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Choices = factory());\n})(this, (function () { 'use strict';\n\n    /******************************************************************************\n    Copyright (c) Microsoft Corporation.\n\n    Permission to use, copy, modify, and/or distribute this software for any\n    purpose with or without fee is hereby granted.\n\n    THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\n    REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\n    AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\n    INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\n    LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\n    OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\n    PERFORMANCE OF THIS SOFTWARE.\n    ***************************************************************************** */\n    /* global Reflect, Promise, SuppressedError, Symbol */\n\n    var extendStatics = function (d, b) {\n      extendStatics = Object.setPrototypeOf || {\n        __proto__: []\n      } instanceof Array && function (d, b) {\n        d.__proto__ = b;\n      } || function (d, b) {\n        for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p];\n      };\n      return extendStatics(d, b);\n    };\n    function __extends(d, b) {\n      if (typeof b !== \"function\" && b !== null) throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\n      extendStatics(d, b);\n      function __() {\n        this.constructor = d;\n      }\n      d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\n    }\n    var __assign = function () {\n      __assign = Object.assign || function __assign(t) {\n        for (var s, i = 1, n = arguments.length; i < n; i++) {\n          s = arguments[i];\n          for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\n        }\n        return t;\n      };\n      return __assign.apply(this, arguments);\n    };\n    typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\n      var e = new Error(message);\n      return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\n    };\n\n    var ActionType = {\n        ADD_CHOICE: 'ADD_CHOICE',\n        REMOVE_CHOICE: 'REMOVE_CHOICE',\n        FILTER_CHOICES: 'FILTER_CHOICES',\n        ACTIVATE_CHOICES: 'ACTIVATE_CHOICES',\n        CLEAR_CHOICES: 'CLEAR_CHOICES',\n        ADD_GROUP: 'ADD_GROUP',\n        ADD_ITEM: 'ADD_ITEM',\n        REMOVE_ITEM: 'REMOVE_ITEM',\n        HIGHLIGHT_ITEM: 'HIGHLIGHT_ITEM',\n    };\n\n    var EventType = {\n        showDropdown: 'showDropdown',\n        hideDropdown: 'hideDropdown',\n        change: 'change',\n        choice: 'choice',\n        search: 'search',\n        addItem: 'addItem',\n        removeItem: 'removeItem',\n        highlightItem: 'highlightItem',\n        highlightChoice: 'highlightChoice',\n        unhighlightItem: 'unhighlightItem',\n    };\n\n    var KeyCodeMap = {\n        TAB_KEY: 9,\n        SHIFT_KEY: 16,\n        BACK_KEY: 46,\n        DELETE_KEY: 8,\n        ENTER_KEY: 13,\n        A_KEY: 65,\n        ESC_KEY: 27,\n        UP_KEY: 38,\n        DOWN_KEY: 40,\n        PAGE_UP_KEY: 33,\n        PAGE_DOWN_KEY: 34,\n    };\n\n    var ObjectsInConfig = ['fuseOptions', 'classNames'];\n\n    var PassedElementTypes = {\n        Text: 'text',\n        SelectOne: 'select-one',\n        SelectMultiple: 'select-multiple',\n    };\n\n    var addChoice = function (choice) { return ({\n        type: ActionType.ADD_CHOICE,\n        choice: choice,\n    }); };\n    var removeChoice = function (choice) { return ({\n        type: ActionType.REMOVE_CHOICE,\n        choice: choice,\n    }); };\n    var filterChoices = function (results) { return ({\n        type: ActionType.FILTER_CHOICES,\n        results: results,\n    }); };\n    var activateChoices = function (active) {\n        return ({\n            type: ActionType.ACTIVATE_CHOICES,\n            active: active,\n        });\n    };\n\n    var addGroup = function (group) { return ({\n        type: ActionType.ADD_GROUP,\n        group: group,\n    }); };\n\n    var addItem = function (item) { return ({\n        type: ActionType.ADD_ITEM,\n        item: item,\n    }); };\n    var removeItem$1 = function (item) { return ({\n        type: ActionType.REMOVE_ITEM,\n        item: item,\n    }); };\n    var highlightItem = function (item, highlighted) { return ({\n        type: ActionType.HIGHLIGHT_ITEM,\n        item: item,\n        highlighted: highlighted,\n    }); };\n\n    var getRandomNumber = function (min, max) { return Math.floor(Math.random() * (max - min) + min); };\n    var generateChars = function (length) {\n        return Array.from({ length: length }, function () { return getRandomNumber(0, 36).toString(36); }).join('');\n    };\n    var generateId = function (element, prefix) {\n        var id = element.id || (element.name && \"\".concat(element.name, \"-\").concat(generateChars(2))) || generateChars(4);\n        id = id.replace(/(:|\\.|\\[|\\]|,)/g, '');\n        id = \"\".concat(prefix, \"-\").concat(id);\n        return id;\n    };\n    var getAdjacentEl = function (startEl, selector, direction) {\n        if (direction === void 0) { direction = 1; }\n        var prop = \"\".concat(direction > 0 ? 'next' : 'previous', \"ElementSibling\");\n        var sibling = startEl[prop];\n        while (sibling) {\n            if (sibling.matches(selector)) {\n                return sibling;\n            }\n            sibling = sibling[prop];\n        }\n        return null;\n    };\n    var isScrolledIntoView = function (element, parent, direction) {\n        if (direction === void 0) { direction = 1; }\n        var isVisible;\n        if (direction > 0) {\n            // In view from bottom\n            isVisible = parent.scrollTop + parent.offsetHeight >= element.offsetTop + element.offsetHeight;\n        }\n        else {\n            // In view from top\n            isVisible = element.offsetTop >= parent.scrollTop;\n        }\n        return isVisible;\n    };\n    var sanitise = function (value) {\n        if (typeof value !== 'string') {\n            if (value === null || value === undefined) {\n                return '';\n            }\n            if (typeof value === 'object') {\n                if ('raw' in value) {\n                    return sanitise(value.raw);\n                }\n                if ('trusted' in value) {\n                    return value.trusted;\n                }\n            }\n            return value;\n        }\n        return value\n            .replace(/&/g, '&amp;')\n            .replace(/>/g, '&gt;')\n            .replace(/</g, '&lt;')\n            .replace(/'/g, '&#039;')\n            .replace(/\"/g, '&quot;');\n    };\n    var strToEl = (function () {\n        var tmpEl = document.createElement('div');\n        return function (str) {\n            tmpEl.innerHTML = str.trim();\n            var firstChild = tmpEl.children[0];\n            while (tmpEl.firstChild) {\n                tmpEl.removeChild(tmpEl.firstChild);\n            }\n            return firstChild;\n        };\n    })();\n    var resolveStringFunction = function (fn) {\n        return typeof fn === 'function' ? fn() : fn;\n    };\n    var unwrapStringForRaw = function (s) {\n        if (typeof s === 'string') {\n            return s;\n        }\n        if (typeof s === 'object') {\n            if ('trusted' in s) {\n                return s.trusted;\n            }\n            if ('raw' in s) {\n                return s.raw;\n            }\n        }\n        return '';\n    };\n    var unwrapStringForEscaped = function (s) {\n        if (typeof s === 'string') {\n            return s;\n        }\n        if (typeof s === 'object') {\n            if ('escaped' in s) {\n                return s.escaped;\n            }\n            if ('trusted' in s) {\n                return s.trusted;\n            }\n        }\n        return '';\n    };\n    var getChoiceForOutput = function (choice, keyCode) {\n        return {\n            id: choice.id,\n            highlighted: choice.highlighted,\n            labelClass: choice.labelClass,\n            labelDescription: unwrapStringForRaw(choice.labelDescription),\n            customProperties: choice.customProperties,\n            disabled: choice.disabled,\n            active: choice.active,\n            label: choice.label,\n            placeholder: choice.placeholder,\n            value: choice.value,\n            groupValue: choice.group ? choice.group.label : undefined,\n            element: choice.element,\n            keyCode: keyCode,\n        };\n    };\n    var resolveNoticeFunction = function (fn, value, item) {\n        return typeof fn === 'function' ? fn(sanitise(value), unwrapStringForRaw(value), item) : fn;\n    };\n    var escapeForTemplate = function (allowHTML, s) {\n        return allowHTML ? unwrapStringForEscaped(s) : sanitise(s);\n    };\n    var setElementHtml = function (el, allowHtml, html) {\n        el.innerHTML = escapeForTemplate(allowHtml, html);\n    };\n    var sortByAlpha = function (_a, _b) {\n        var value = _a.value, _c = _a.label, label = _c === void 0 ? value : _c;\n        var value2 = _b.value, _d = _b.label, label2 = _d === void 0 ? value2 : _d;\n        return unwrapStringForRaw(label).localeCompare(unwrapStringForRaw(label2), [], {\n            sensitivity: 'base',\n            ignorePunctuation: true,\n            numeric: true,\n        });\n    };\n    var sortByRank = function (a, b) {\n        return a.rank - b.rank;\n    };\n    var dispatchEvent = function (element, type, customArgs) {\n        if (customArgs === void 0) { customArgs = null; }\n        var event = new CustomEvent(type, {\n            detail: customArgs,\n            bubbles: true,\n            cancelable: true,\n        });\n        return element.dispatchEvent(event);\n    };\n    /**\n     * Returns an array of keys present on the first but missing on the second object\n     */\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    var diff = function (a, b) {\n        var aKeys = Object.keys(a).sort();\n        var bKeys = Object.keys(b).sort();\n        return aKeys.filter(function (i) { return bKeys.indexOf(i) < 0; });\n    };\n    var getClassNames = function (ClassNames) {\n        return Array.isArray(ClassNames) ? ClassNames : [ClassNames];\n    };\n    var getClassNamesSelector = function (option) {\n        if (option && Array.isArray(option)) {\n            return option\n                .map(function (item) {\n                return \".\".concat(item);\n            })\n                .join('');\n        }\n        return \".\".concat(option);\n    };\n    var addClassesToElement = function (element, className) {\n        var _a;\n        (_a = element.classList).add.apply(_a, getClassNames(className));\n    };\n    var removeClassesFromElement = function (element, className) {\n        var _a;\n        (_a = element.classList).remove.apply(_a, getClassNames(className));\n    };\n    var parseCustomProperties = function (customProperties) {\n        if (typeof customProperties !== 'undefined') {\n            try {\n                return JSON.parse(customProperties);\n            }\n            catch (e) {\n                return customProperties;\n            }\n        }\n        return {};\n    };\n    var updateClassList = function (item, add, remove) {\n        var itemEl = item.itemEl;\n        if (itemEl) {\n            removeClassesFromElement(itemEl, remove);\n            addClassesToElement(itemEl, add);\n        }\n    };\n\n    var Dropdown = /** @class */ (function () {\n        function Dropdown(_a) {\n            var element = _a.element, type = _a.type, classNames = _a.classNames;\n            this.element = element;\n            this.classNames = classNames;\n            this.type = type;\n            this.isActive = false;\n        }\n        /**\n         * Show dropdown to user by adding active state class\n         */\n        Dropdown.prototype.show = function () {\n            addClassesToElement(this.element, this.classNames.activeState);\n            this.element.setAttribute('aria-expanded', 'true');\n            this.isActive = true;\n            return this;\n        };\n        /**\n         * Hide dropdown from user\n         */\n        Dropdown.prototype.hide = function () {\n            removeClassesFromElement(this.element, this.classNames.activeState);\n            this.element.setAttribute('aria-expanded', 'false');\n            this.isActive = false;\n            return this;\n        };\n        return Dropdown;\n    }());\n\n    var Container = /** @class */ (function () {\n        function Container(_a) {\n            var element = _a.element, type = _a.type, classNames = _a.classNames, position = _a.position;\n            this.element = element;\n            this.classNames = classNames;\n            this.type = type;\n            this.position = position;\n            this.isOpen = false;\n            this.isFlipped = false;\n            this.isDisabled = false;\n            this.isLoading = false;\n        }\n        /**\n         * Determine whether container should be flipped based on passed\n         * dropdown position\n         */\n        Container.prototype.shouldFlip = function (dropdownPos, dropdownHeight) {\n            // If flip is enabled and the dropdown bottom position is\n            // greater than the window height flip the dropdown.\n            var shouldFlip = false;\n            if (this.position === 'auto') {\n                shouldFlip =\n                    this.element.getBoundingClientRect().top - dropdownHeight >= 0 &&\n                        !window.matchMedia(\"(min-height: \".concat(dropdownPos + 1, \"px)\")).matches;\n            }\n            else if (this.position === 'top') {\n                shouldFlip = true;\n            }\n            return shouldFlip;\n        };\n        Container.prototype.setActiveDescendant = function (activeDescendantID) {\n            this.element.setAttribute('aria-activedescendant', activeDescendantID);\n        };\n        Container.prototype.removeActiveDescendant = function () {\n            this.element.removeAttribute('aria-activedescendant');\n        };\n        Container.prototype.open = function (dropdownPos, dropdownHeight) {\n            addClassesToElement(this.element, this.classNames.openState);\n            this.element.setAttribute('aria-expanded', 'true');\n            this.isOpen = true;\n            if (this.shouldFlip(dropdownPos, dropdownHeight)) {\n                addClassesToElement(this.element, this.classNames.flippedState);\n                this.isFlipped = true;\n            }\n        };\n        Container.prototype.close = function () {\n            removeClassesFromElement(this.element, this.classNames.openState);\n            this.element.setAttribute('aria-expanded', 'false');\n            this.removeActiveDescendant();\n            this.isOpen = false;\n            // A dropdown flips if it does not have space within the page\n            if (this.isFlipped) {\n                removeClassesFromElement(this.element, this.classNames.flippedState);\n                this.isFlipped = false;\n            }\n        };\n        Container.prototype.addFocusState = function () {\n            addClassesToElement(this.element, this.classNames.focusState);\n        };\n        Container.prototype.removeFocusState = function () {\n            removeClassesFromElement(this.element, this.classNames.focusState);\n        };\n        Container.prototype.addInvalidState = function () {\n            addClassesToElement(this.element, this.classNames.invalidState);\n        };\n        Container.prototype.removeInvalidState = function () {\n            removeClassesFromElement(this.element, this.classNames.invalidState);\n        };\n        Container.prototype.enable = function () {\n            removeClassesFromElement(this.element, this.classNames.disabledState);\n            this.element.removeAttribute('aria-disabled');\n            if (this.type === PassedElementTypes.SelectOne) {\n                this.element.setAttribute('tabindex', '0');\n            }\n            this.isDisabled = false;\n        };\n        Container.prototype.disable = function () {\n            addClassesToElement(this.element, this.classNames.disabledState);\n            this.element.setAttribute('aria-disabled', 'true');\n            if (this.type === PassedElementTypes.SelectOne) {\n                this.element.setAttribute('tabindex', '-1');\n            }\n            this.isDisabled = true;\n        };\n        Container.prototype.wrap = function (element) {\n            var el = this.element;\n            var parentNode = element.parentNode;\n            if (parentNode) {\n                if (element.nextSibling) {\n                    parentNode.insertBefore(el, element.nextSibling);\n                }\n                else {\n                    parentNode.appendChild(el);\n                }\n            }\n            el.appendChild(element);\n        };\n        Container.prototype.unwrap = function (element) {\n            var el = this.element;\n            var parentNode = el.parentNode;\n            if (parentNode) {\n                // Move passed element outside this element\n                parentNode.insertBefore(element, el);\n                // Remove this element\n                parentNode.removeChild(el);\n            }\n        };\n        Container.prototype.addLoadingState = function () {\n            addClassesToElement(this.element, this.classNames.loadingState);\n            this.element.setAttribute('aria-busy', 'true');\n            this.isLoading = true;\n        };\n        Container.prototype.removeLoadingState = function () {\n            removeClassesFromElement(this.element, this.classNames.loadingState);\n            this.element.removeAttribute('aria-busy');\n            this.isLoading = false;\n        };\n        return Container;\n    }());\n\n    var Input = /** @class */ (function () {\n        function Input(_a) {\n            var element = _a.element, type = _a.type, classNames = _a.classNames, preventPaste = _a.preventPaste;\n            this.element = element;\n            this.type = type;\n            this.classNames = classNames;\n            this.preventPaste = preventPaste;\n            this.isFocussed = this.element.isEqualNode(document.activeElement);\n            this.isDisabled = element.disabled;\n            this._onPaste = this._onPaste.bind(this);\n            this._onInput = this._onInput.bind(this);\n            this._onFocus = this._onFocus.bind(this);\n            this._onBlur = this._onBlur.bind(this);\n        }\n        Object.defineProperty(Input.prototype, \"placeholder\", {\n            set: function (placeholder) {\n                this.element.placeholder = placeholder;\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(Input.prototype, \"value\", {\n            get: function () {\n                return this.element.value;\n            },\n            set: function (value) {\n                this.element.value = value;\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Input.prototype.addEventListeners = function () {\n            var el = this.element;\n            el.addEventListener('paste', this._onPaste);\n            el.addEventListener('input', this._onInput, {\n                passive: true,\n            });\n            el.addEventListener('focus', this._onFocus, {\n                passive: true,\n            });\n            el.addEventListener('blur', this._onBlur, {\n                passive: true,\n            });\n        };\n        Input.prototype.removeEventListeners = function () {\n            var el = this.element;\n            el.removeEventListener('input', this._onInput);\n            el.removeEventListener('paste', this._onPaste);\n            el.removeEventListener('focus', this._onFocus);\n            el.removeEventListener('blur', this._onBlur);\n        };\n        Input.prototype.enable = function () {\n            var el = this.element;\n            el.removeAttribute('disabled');\n            this.isDisabled = false;\n        };\n        Input.prototype.disable = function () {\n            var el = this.element;\n            el.setAttribute('disabled', '');\n            this.isDisabled = true;\n        };\n        Input.prototype.focus = function () {\n            if (!this.isFocussed) {\n                this.element.focus();\n            }\n        };\n        Input.prototype.blur = function () {\n            if (this.isFocussed) {\n                this.element.blur();\n            }\n        };\n        Input.prototype.clear = function (setWidth) {\n            if (setWidth === void 0) { setWidth = true; }\n            this.element.value = '';\n            if (setWidth) {\n                this.setWidth();\n            }\n            return this;\n        };\n        /**\n         * Set the correct input width based on placeholder\n         * value or input value\n         */\n        Input.prototype.setWidth = function () {\n            // Resize input to contents or placeholder\n            var element = this.element;\n            element.style.minWidth = \"\".concat(element.placeholder.length + 1, \"ch\");\n            element.style.width = \"\".concat(element.value.length + 1, \"ch\");\n        };\n        Input.prototype.setActiveDescendant = function (activeDescendantID) {\n            this.element.setAttribute('aria-activedescendant', activeDescendantID);\n        };\n        Input.prototype.removeActiveDescendant = function () {\n            this.element.removeAttribute('aria-activedescendant');\n        };\n        Input.prototype._onInput = function () {\n            if (this.type !== PassedElementTypes.SelectOne) {\n                this.setWidth();\n            }\n        };\n        Input.prototype._onPaste = function (event) {\n            if (this.preventPaste) {\n                event.preventDefault();\n            }\n        };\n        Input.prototype._onFocus = function () {\n            this.isFocussed = true;\n        };\n        Input.prototype._onBlur = function () {\n            this.isFocussed = false;\n        };\n        return Input;\n    }());\n\n    var SCROLLING_SPEED = 4;\n\n    var List = /** @class */ (function () {\n        function List(_a) {\n            var element = _a.element;\n            this.element = element;\n            this.scrollPos = this.element.scrollTop;\n            this.height = this.element.offsetHeight;\n        }\n        List.prototype.prepend = function (node) {\n            var child = this.element.firstElementChild;\n            if (child) {\n                this.element.insertBefore(node, child);\n            }\n            else {\n                this.element.append(node);\n            }\n        };\n        List.prototype.scrollToTop = function () {\n            this.element.scrollTop = 0;\n        };\n        List.prototype.scrollToChildElement = function (element, direction) {\n            var _this = this;\n            if (!element) {\n                return;\n            }\n            var listHeight = this.element.offsetHeight;\n            // Scroll position of dropdown\n            var listScrollPosition = this.element.scrollTop + listHeight;\n            var elementHeight = element.offsetHeight;\n            // Distance from bottom of element to top of parent\n            var elementPos = element.offsetTop + elementHeight;\n            // Difference between the element and scroll position\n            var destination = direction > 0 ? this.element.scrollTop + elementPos - listScrollPosition : element.offsetTop;\n            requestAnimationFrame(function () {\n                _this._animateScroll(destination, direction);\n            });\n        };\n        List.prototype._scrollDown = function (scrollPos, strength, destination) {\n            var easing = (destination - scrollPos) / strength;\n            var distance = easing > 1 ? easing : 1;\n            this.element.scrollTop = scrollPos + distance;\n        };\n        List.prototype._scrollUp = function (scrollPos, strength, destination) {\n            var easing = (scrollPos - destination) / strength;\n            var distance = easing > 1 ? easing : 1;\n            this.element.scrollTop = scrollPos - distance;\n        };\n        List.prototype._animateScroll = function (destination, direction) {\n            var _this = this;\n            var strength = SCROLLING_SPEED;\n            var choiceListScrollTop = this.element.scrollTop;\n            var continueAnimation = false;\n            if (direction > 0) {\n                this._scrollDown(choiceListScrollTop, strength, destination);\n                if (choiceListScrollTop < destination) {\n                    continueAnimation = true;\n                }\n            }\n            else {\n                this._scrollUp(choiceListScrollTop, strength, destination);\n                if (choiceListScrollTop > destination) {\n                    continueAnimation = true;\n                }\n            }\n            if (continueAnimation) {\n                requestAnimationFrame(function () {\n                    _this._animateScroll(destination, direction);\n                });\n            }\n        };\n        return List;\n    }());\n\n    var WrappedElement = /** @class */ (function () {\n        function WrappedElement(_a) {\n            var element = _a.element, classNames = _a.classNames;\n            this.element = element;\n            this.classNames = classNames;\n            this.isDisabled = false;\n        }\n        Object.defineProperty(WrappedElement.prototype, \"isActive\", {\n            get: function () {\n                return this.element.dataset.choice === 'active';\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(WrappedElement.prototype, \"dir\", {\n            get: function () {\n                return this.element.dir;\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(WrappedElement.prototype, \"value\", {\n            get: function () {\n                return this.element.value;\n            },\n            set: function (value) {\n                this.element.setAttribute('value', value);\n                this.element.value = value;\n            },\n            enumerable: false,\n            configurable: true\n        });\n        WrappedElement.prototype.conceal = function () {\n            var el = this.element;\n            // Hide passed input\n            addClassesToElement(el, this.classNames.input);\n            el.hidden = true;\n            // Remove element from tab index\n            el.tabIndex = -1;\n            // Backup original styles if any\n            var origStyle = el.getAttribute('style');\n            if (origStyle) {\n                el.setAttribute('data-choice-orig-style', origStyle);\n            }\n            el.setAttribute('data-choice', 'active');\n        };\n        WrappedElement.prototype.reveal = function () {\n            var el = this.element;\n            // Reinstate passed element\n            removeClassesFromElement(el, this.classNames.input);\n            el.hidden = false;\n            el.removeAttribute('tabindex');\n            // Recover original styles if any\n            var origStyle = el.getAttribute('data-choice-orig-style');\n            if (origStyle) {\n                el.removeAttribute('data-choice-orig-style');\n                el.setAttribute('style', origStyle);\n            }\n            else {\n                el.removeAttribute('style');\n            }\n            el.removeAttribute('data-choice');\n        };\n        WrappedElement.prototype.enable = function () {\n            this.element.removeAttribute('disabled');\n            this.element.disabled = false;\n            this.isDisabled = false;\n        };\n        WrappedElement.prototype.disable = function () {\n            this.element.setAttribute('disabled', '');\n            this.element.disabled = true;\n            this.isDisabled = true;\n        };\n        WrappedElement.prototype.triggerEvent = function (eventType, data) {\n            dispatchEvent(this.element, eventType, data || {});\n        };\n        return WrappedElement;\n    }());\n\n    var WrappedInput = /** @class */ (function (_super) {\n        __extends(WrappedInput, _super);\n        function WrappedInput() {\n            return _super !== null && _super.apply(this, arguments) || this;\n        }\n        return WrappedInput;\n    }(WrappedElement));\n\n    var coerceBool = function (arg, defaultValue) {\n        if (defaultValue === void 0) { defaultValue = true; }\n        return typeof arg === 'undefined' ? defaultValue : !!arg;\n    };\n    var stringToHtmlClass = function (input) {\n        if (typeof input === 'string') {\n            // eslint-disable-next-line no-param-reassign\n            input = input.split(' ').filter(function (s) { return s.length; });\n        }\n        if (Array.isArray(input) && input.length) {\n            return input;\n        }\n        return undefined;\n    };\n    var mapInputToChoice = function (value, allowGroup, allowRawString) {\n        if (allowRawString === void 0) { allowRawString = true; }\n        if (typeof value === 'string') {\n            var sanitisedValue = sanitise(value);\n            var userValue = allowRawString || sanitisedValue === value ? value : { escaped: sanitisedValue, raw: value };\n            var result_1 = mapInputToChoice({\n                value: value,\n                label: userValue,\n                selected: true,\n            }, false);\n            return result_1;\n        }\n        var groupOrChoice = value;\n        if ('choices' in groupOrChoice) {\n            if (!allowGroup) {\n                // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/optgroup\n                throw new TypeError(\"optGroup is not allowed\");\n            }\n            var group = groupOrChoice;\n            var choices = group.choices.map(function (e) { return mapInputToChoice(e, false); });\n            var result_2 = {\n                id: 0, // actual ID will be assigned during _addGroup\n                label: unwrapStringForRaw(group.label) || group.value,\n                active: !!choices.length,\n                disabled: !!group.disabled,\n                choices: choices,\n            };\n            return result_2;\n        }\n        var choice = groupOrChoice;\n        var result = {\n            id: 0, // actual ID will be assigned during _addChoice\n            group: null, // actual group will be assigned during _addGroup but before _addChoice\n            score: 0, // used in search\n            rank: 0, // used in search, stable sort order\n            value: choice.value,\n            label: choice.label || choice.value,\n            active: coerceBool(choice.active),\n            selected: coerceBool(choice.selected, false),\n            disabled: coerceBool(choice.disabled, false),\n            placeholder: coerceBool(choice.placeholder, false),\n            highlighted: false,\n            labelClass: stringToHtmlClass(choice.labelClass),\n            labelDescription: choice.labelDescription,\n            customProperties: choice.customProperties,\n        };\n        return result;\n    };\n\n    var isHtmlInputElement = function (e) { return e.tagName === 'INPUT'; };\n    var isHtmlSelectElement = function (e) { return e.tagName === 'SELECT'; };\n    var isHtmlOption = function (e) { return e.tagName === 'OPTION'; };\n    var isHtmlOptgroup = function (e) { return e.tagName === 'OPTGROUP'; };\n\n    var WrappedSelect = /** @class */ (function (_super) {\n        __extends(WrappedSelect, _super);\n        function WrappedSelect(_a) {\n            var element = _a.element, classNames = _a.classNames, template = _a.template, extractPlaceholder = _a.extractPlaceholder;\n            var _this = _super.call(this, { element: element, classNames: classNames }) || this;\n            _this.template = template;\n            _this.extractPlaceholder = extractPlaceholder;\n            return _this;\n        }\n        Object.defineProperty(WrappedSelect.prototype, \"placeholderOption\", {\n            get: function () {\n                return (this.element.querySelector('option[value=\"\"]') ||\n                    // Backward compatibility layer for the non-standard placeholder attribute supported in older versions.\n                    this.element.querySelector('option[placeholder]'));\n            },\n            enumerable: false,\n            configurable: true\n        });\n        WrappedSelect.prototype.addOptions = function (choices) {\n            var _this = this;\n            var fragment = document.createDocumentFragment();\n            choices.forEach(function (obj) {\n                var choice = obj;\n                if (choice.element) {\n                    return;\n                }\n                var option = _this.template(choice);\n                fragment.appendChild(option);\n                choice.element = option;\n            });\n            this.element.appendChild(fragment);\n        };\n        WrappedSelect.prototype.optionsAsChoices = function () {\n            var _this = this;\n            var choices = [];\n            this.element.querySelectorAll(':scope > option, :scope > optgroup').forEach(function (e) {\n                if (isHtmlOption(e)) {\n                    choices.push(_this._optionToChoice(e));\n                }\n                else if (isHtmlOptgroup(e)) {\n                    choices.push(_this._optgroupToChoice(e));\n                }\n                // todo: hr as empty optgroup, requires displaying empty opt-groups to be useful\n            });\n            return choices;\n        };\n        // eslint-disable-next-line class-methods-use-this\n        WrappedSelect.prototype._optionToChoice = function (option) {\n            // option.value returns the label if there is no value attribute, which can break legacy placeholder attribute support\n            if (!option.hasAttribute('value') && option.hasAttribute('placeholder')) {\n                option.setAttribute('value', '');\n                option.value = '';\n            }\n            return {\n                id: 0,\n                group: null,\n                score: 0,\n                rank: 0,\n                value: option.value,\n                // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/option\n                // This attribute is text for the label indicating the meaning of the option. If the `label` attribute isn't defined, its value is that of the element text content (ie `innerText`).\n                label: option.label,\n                element: option,\n                active: true,\n                // this returns true if nothing is selected on initial load, which will break placeholder support\n                selected: this.extractPlaceholder ? option.selected : option.hasAttribute('selected'),\n                disabled: option.disabled,\n                highlighted: false,\n                placeholder: this.extractPlaceholder && (!option.value || option.hasAttribute('placeholder')),\n                labelClass: typeof option.dataset.labelClass !== 'undefined' ? stringToHtmlClass(option.dataset.labelClass) : undefined,\n                labelDescription: typeof option.dataset.labelDescription !== 'undefined'\n                    ? { trusted: option.dataset.labelDescription }\n                    : undefined,\n                customProperties: parseCustomProperties(option.dataset.customProperties),\n            };\n        };\n        WrappedSelect.prototype._optgroupToChoice = function (optgroup) {\n            var _this = this;\n            var options = optgroup.querySelectorAll('option');\n            var choices = Array.from(options).map(function (option) { return _this._optionToChoice(option); });\n            return {\n                id: 0,\n                label: optgroup.label || '',\n                element: optgroup,\n                active: !!choices.length,\n                disabled: optgroup.disabled,\n                choices: choices,\n            };\n        };\n        return WrappedSelect;\n    }(WrappedElement));\n\n    var DEFAULT_CLASSNAMES = {\n        containerOuter: ['choices'],\n        containerInner: ['choices__inner'],\n        input: ['choices__input'],\n        inputCloned: ['choices__input--cloned'],\n        list: ['choices__list'],\n        listItems: ['choices__list--multiple'],\n        listSingle: ['choices__list--single'],\n        listDropdown: ['choices__list--dropdown'],\n        item: ['choices__item'],\n        itemSelectable: ['choices__item--selectable'],\n        itemDisabled: ['choices__item--disabled'],\n        itemChoice: ['choices__item--choice'],\n        description: ['choices__description'],\n        placeholder: ['choices__placeholder'],\n        group: ['choices__group'],\n        groupHeading: ['choices__heading'],\n        button: ['choices__button'],\n        activeState: ['is-active'],\n        focusState: ['is-focused'],\n        openState: ['is-open'],\n        disabledState: ['is-disabled'],\n        highlightedState: ['is-highlighted'],\n        selectedState: ['is-selected'],\n        flippedState: ['is-flipped'],\n        loadingState: ['is-loading'],\n        invalidState: ['is-invalid'],\n        notice: ['choices__notice'],\n        addChoice: ['choices__item--selectable', 'add-choice'],\n        noResults: ['has-no-results'],\n        noChoices: ['has-no-choices'],\n    };\n    var DEFAULT_CONFIG = {\n        items: [],\n        choices: [],\n        silent: false,\n        renderChoiceLimit: -1,\n        maxItemCount: -1,\n        closeDropdownOnSelect: 'auto',\n        singleModeForMultiSelect: false,\n        addChoices: false,\n        addItems: true,\n        addItemFilter: function (value) { return !!value && value !== ''; },\n        removeItems: true,\n        removeItemButton: false,\n        removeItemButtonAlignLeft: false,\n        editItems: false,\n        allowHTML: false,\n        allowHtmlUserInput: false,\n        duplicateItemsAllowed: true,\n        delimiter: ',',\n        paste: true,\n        searchEnabled: true,\n        searchChoices: true,\n        searchDisabledChoices: false,\n        searchFloor: 1,\n        searchResultLimit: 4,\n        searchFields: ['label', 'value'],\n        position: 'auto',\n        resetScrollPosition: true,\n        shouldSort: true,\n        shouldSortItems: false,\n        sorter: sortByAlpha,\n        shadowRoot: null,\n        placeholder: true,\n        placeholderValue: null,\n        searchPlaceholderValue: null,\n        prependValue: null,\n        appendValue: null,\n        renderSelectedChoices: 'auto',\n        searchRenderSelectedChoices: true,\n        loadingText: 'Loading...',\n        noResultsText: 'No results found',\n        noChoicesText: 'No choices to choose from',\n        itemSelectText: 'Press to select',\n        uniqueItemText: 'Only unique values can be added',\n        customAddItemText: 'Only values matching specific conditions can be added',\n        addItemText: function (value) { return \"Press Enter to add <b>\\\"\".concat(value, \"\\\"</b>\"); },\n        removeItemIconText: function () { return \"Remove item\"; },\n        removeItemLabelText: function (value, _valueRaw, i) {\n            return \"Remove item: \".concat(i ? sanitise(i.label) : value);\n        },\n        maxItemText: function (maxItemCount) { return \"Only \".concat(maxItemCount, \" values can be added\"); },\n        valueComparer: function (value1, value2) { return value1 === value2; },\n        fuseOptions: {\n            includeScore: true,\n        },\n        labelId: '',\n        callbackOnInit: null,\n        callbackOnCreateTemplates: null,\n        classNames: DEFAULT_CLASSNAMES,\n        appendGroupInSearch: false,\n    };\n\n    var removeItem = function (item) {\n        var itemEl = item.itemEl;\n        if (itemEl) {\n            itemEl.remove();\n            item.itemEl = undefined;\n        }\n    };\n    function items(s, action, context) {\n        var state = s;\n        var update = true;\n        switch (action.type) {\n            case ActionType.ADD_ITEM: {\n                action.item.selected = true;\n                var el = action.item.element;\n                if (el) {\n                    el.selected = true;\n                    el.setAttribute('selected', '');\n                }\n                state.push(action.item);\n                break;\n            }\n            case ActionType.REMOVE_ITEM: {\n                action.item.selected = false;\n                var el = action.item.element;\n                if (el) {\n                    el.selected = false;\n                    el.removeAttribute('selected');\n                    // For a select-one, if all options are deselected, the first item is selected. To set a black value, select.value needs to be set\n                    var select = el.parentElement;\n                    if (select && isHtmlSelectElement(select) && select.type === PassedElementTypes.SelectOne) {\n                        select.value = '';\n                    }\n                }\n                // this is mixing concerns, but this is *so much faster*\n                removeItem(action.item);\n                state = state.filter(function (choice) { return choice.id !== action.item.id; });\n                break;\n            }\n            case ActionType.REMOVE_CHOICE: {\n                removeItem(action.choice);\n                state = state.filter(function (item) { return item.id !== action.choice.id; });\n                break;\n            }\n            case ActionType.HIGHLIGHT_ITEM: {\n                var highlighted = action.highlighted;\n                var item = state.find(function (obj) { return obj.id === action.item.id; });\n                if (item && item.highlighted !== highlighted) {\n                    item.highlighted = highlighted;\n                    if (context) {\n                        updateClassList(item, highlighted ? context.classNames.highlightedState : context.classNames.selectedState, highlighted ? context.classNames.selectedState : context.classNames.highlightedState);\n                    }\n                }\n                break;\n            }\n            default: {\n                update = false;\n                break;\n            }\n        }\n        return { state: state, update: update };\n    }\n\n    function groups(s, action) {\n        var state = s;\n        var update = true;\n        switch (action.type) {\n            case ActionType.ADD_GROUP: {\n                state.push(action.group);\n                break;\n            }\n            case ActionType.CLEAR_CHOICES: {\n                state = [];\n                break;\n            }\n            default: {\n                update = false;\n                break;\n            }\n        }\n        return { state: state, update: update };\n    }\n\n    /* eslint-disable */\n    function choices(s, action, context) {\n        var state = s;\n        var update = true;\n        switch (action.type) {\n            case ActionType.ADD_CHOICE: {\n                state.push(action.choice);\n                break;\n            }\n            case ActionType.REMOVE_CHOICE: {\n                action.choice.choiceEl = undefined;\n                if (action.choice.group) {\n                    action.choice.group.choices = action.choice.group.choices.filter(function (obj) { return obj.id !== action.choice.id; });\n                }\n                state = state.filter(function (obj) { return obj.id !== action.choice.id; });\n                break;\n            }\n            case ActionType.ADD_ITEM:\n            case ActionType.REMOVE_ITEM: {\n                action.item.choiceEl = undefined;\n                break;\n            }\n            case ActionType.FILTER_CHOICES: {\n                // avoid O(n^2) algorithm complexity when searching/filtering choices\n                var scoreLookup_1 = [];\n                action.results.forEach(function (result) {\n                    scoreLookup_1[result.item.id] = result;\n                });\n                state.forEach(function (choice) {\n                    var result = scoreLookup_1[choice.id];\n                    if (result !== undefined) {\n                        choice.score = result.score;\n                        choice.rank = result.rank;\n                        choice.active = true;\n                    }\n                    else {\n                        choice.score = 0;\n                        choice.rank = 0;\n                        choice.active = false;\n                    }\n                    if (context && context.appendGroupInSearch) {\n                        choice.choiceEl = undefined;\n                    }\n                });\n                break;\n            }\n            case ActionType.ACTIVATE_CHOICES: {\n                state.forEach(function (choice) {\n                    choice.active = action.active;\n                    if (context && context.appendGroupInSearch) {\n                        choice.choiceEl = undefined;\n                    }\n                });\n                break;\n            }\n            case ActionType.CLEAR_CHOICES: {\n                state = [];\n                break;\n            }\n            default: {\n                update = false;\n                break;\n            }\n        }\n        return { state: state, update: update };\n    }\n\n    var reducers = {\n        groups: groups,\n        items: items,\n        choices: choices,\n    };\n    var Store = /** @class */ (function () {\n        function Store(context) {\n            this._state = this.defaultState;\n            this._listeners = [];\n            this._txn = 0;\n            this._context = context;\n        }\n        Object.defineProperty(Store.prototype, \"defaultState\", {\n            // eslint-disable-next-line class-methods-use-this\n            get: function () {\n                return {\n                    groups: [],\n                    items: [],\n                    choices: [],\n                };\n            },\n            enumerable: false,\n            configurable: true\n        });\n        // eslint-disable-next-line class-methods-use-this\n        Store.prototype.changeSet = function (init) {\n            return {\n                groups: init,\n                items: init,\n                choices: init,\n            };\n        };\n        Store.prototype.reset = function () {\n            this._state = this.defaultState;\n            var changes = this.changeSet(true);\n            if (this._txn) {\n                this._changeSet = changes;\n            }\n            else {\n                this._listeners.forEach(function (l) { return l(changes); });\n            }\n        };\n        Store.prototype.subscribe = function (onChange) {\n            this._listeners.push(onChange);\n            return this;\n        };\n        Store.prototype.dispatch = function (action) {\n            var _this = this;\n            var state = this._state;\n            var hasChanges = false;\n            var changes = this._changeSet || this.changeSet(false);\n            Object.keys(reducers).forEach(function (key) {\n                var stateUpdate = reducers[key](state[key], action, _this._context);\n                if (stateUpdate.update) {\n                    hasChanges = true;\n                    changes[key] = true;\n                    state[key] = stateUpdate.state;\n                }\n            });\n            if (hasChanges) {\n                if (this._txn) {\n                    this._changeSet = changes;\n                }\n                else {\n                    this._listeners.forEach(function (l) { return l(changes); });\n                }\n            }\n        };\n        Store.prototype.withTxn = function (func) {\n            this._txn++;\n            try {\n                func();\n            }\n            finally {\n                this._txn = Math.max(0, this._txn - 1);\n                if (!this._txn) {\n                    var changeSet_1 = this._changeSet;\n                    if (changeSet_1) {\n                        this._changeSet = undefined;\n                        this._listeners.forEach(function (l) { return l(changeSet_1); });\n                    }\n                }\n            }\n        };\n        Object.defineProperty(Store.prototype, \"state\", {\n            /**\n             * Get store object\n             */\n            get: function () {\n                return this._state;\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(Store.prototype, \"items\", {\n            /**\n             * Get items from store\n             */\n            get: function () {\n                return this.state.items;\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(Store.prototype, \"highlightedActiveItems\", {\n            /**\n             * Get highlighted items from store\n             */\n            get: function () {\n                return this.items.filter(function (item) { return item.active && item.highlighted; });\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(Store.prototype, \"choices\", {\n            /**\n             * Get choices from store\n             */\n            get: function () {\n                return this.state.choices;\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(Store.prototype, \"activeChoices\", {\n            /**\n             * Get active choices from store\n             */\n            get: function () {\n                return this.choices.filter(function (choice) { return choice.active; });\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(Store.prototype, \"searchableChoices\", {\n            /**\n             * Get choices that can be searched (excluding placeholders or disabled choices)\n             */\n            get: function () {\n                var context = this._context;\n                return this.choices.filter(function (choice) { return !choice.placeholder && (context.searchDisabledChoices || !choice.disabled); });\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(Store.prototype, \"groups\", {\n            /**\n             * Get groups from store\n             */\n            get: function () {\n                return this.state.groups;\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(Store.prototype, \"activeGroups\", {\n            /**\n             * Get active groups from store\n             */\n            get: function () {\n                var _this = this;\n                return this.state.groups.filter(function (group) {\n                    var isActive = group.active && !group.disabled;\n                    var hasActiveOptions = _this.state.choices.some(function (choice) { return choice.active && !choice.disabled; });\n                    return isActive && hasActiveOptions;\n                }, []);\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Store.prototype.inTxn = function () {\n            return this._txn > 0;\n        };\n        /**\n         * Get single choice by it's ID\n         */\n        Store.prototype.getChoiceById = function (id) {\n            return this.activeChoices.find(function (choice) { return choice.id === id; });\n        };\n        /**\n         * Get group by group id\n         */\n        Store.prototype.getGroupById = function (id) {\n            return this.groups.find(function (group) { return group.id === id; });\n        };\n        return Store;\n    }());\n\n    var NoticeTypes = {\n        noChoices: 'no-choices',\n        noResults: 'no-results',\n        addChoice: 'add-choice',\n        generic: '',\n    };\n\n    function kmpSearch(pattern, text) {\n        if (pattern.length === 0) {\n            return 0; // Immediate match\n        }\n        // Compute longest suffix-prefix table\n        var lsp = [0]; // Base case\n        for (var i = 1; i < pattern.length; i++) {\n            var j_1 = lsp[i - 1]; // Start by assuming we're extending the previous LSP\n            while (j_1 > 0 && pattern.charAt(i) !== pattern.charAt(j_1)) {\n                j_1 = lsp[j_1 - 1];\n            }\n            if (pattern.charAt(i) === pattern.charAt(j_1)) {\n                j_1++;\n            }\n            lsp.push(j_1);\n        }\n        // Walk through text string\n        var j = 0; // Number of chars matched in pattern\n        for (var i = 0; i < text.length; i++) {\n            while (j > 0 && text.charAt(i) !== pattern.charAt(j)) {\n                j = lsp[j - 1]; // Fall back in the pattern\n            }\n            if (text.charAt(i) === pattern.charAt(j)) {\n                j++; // Next char matched, increment position\n                if (j === pattern.length) {\n                    return i - (j - 1);\n                }\n            }\n        }\n        return -1; // Not found\n    }\n    var SearchByKMP = /** @class */ (function () {\n        function SearchByKMP(config) {\n            this._haystack = [];\n            this._fields = config.searchFields;\n        }\n        SearchByKMP.prototype.index = function (data) {\n            this._haystack = data;\n        };\n        SearchByKMP.prototype.reset = function () {\n            this._haystack = [];\n        };\n        SearchByKMP.prototype.isEmptyIndex = function () {\n            return !this._haystack.length;\n        };\n        SearchByKMP.prototype.search = function (_needle) {\n            var fields = this._fields;\n            if (!fields || !fields.length || !_needle) {\n                return [];\n            }\n            var needle = _needle.toLowerCase();\n            var results = [];\n            var count = 0;\n            for (var i = 0, j = this._haystack.length; i < j; i++) {\n                var obj = this._haystack[i];\n                for (var k = 0, l = this._fields.length; k < l; k++) {\n                    var field = this._fields[k];\n                    if (field in obj && kmpSearch(needle, obj[field].toLowerCase()) !== -1) {\n                        results.push({\n                            item: obj,\n                            score: count,\n                            rank: count + 1,\n                        });\n                        count++;\n                        break;\n                    }\n                }\n            }\n            return results;\n        };\n        return SearchByKMP;\n    }());\n\n    function getSearcher(config) {\n        {\n            return new SearchByKMP(config);\n        }\n    }\n\n    /**\n     * Helpers to create HTML elements used by Choices\n     * Can be overridden by providing `callbackOnCreateTemplates` option.\n     * `Choices.defaults.templates` allows access to the default template methods from `callbackOnCreateTemplates`\n     */\n    var isEmptyObject = function (obj) {\n        // eslint-disable-next-line no-restricted-syntax\n        for (var prop in obj) {\n            if (Object.prototype.hasOwnProperty.call(obj, prop)) {\n                return false;\n            }\n        }\n        return true;\n    };\n    var assignCustomProperties = function (el, choice, withCustomProperties) {\n        var dataset = el.dataset;\n        var customProperties = choice.customProperties, labelClass = choice.labelClass, labelDescription = choice.labelDescription;\n        if (labelClass) {\n            dataset.labelClass = getClassNames(labelClass).join(' ');\n        }\n        if (labelDescription) {\n            dataset.labelDescription = unwrapStringForRaw(labelDescription);\n        }\n        if (withCustomProperties && customProperties) {\n            if (typeof customProperties === 'string') {\n                dataset.customProperties = customProperties;\n            }\n            else if (typeof customProperties === 'object' && !isEmptyObject(customProperties)) {\n                dataset.customProperties = JSON.stringify(customProperties);\n            }\n        }\n    };\n    var addAriaLabel = function (docRoot, id, element) {\n        var label = id && docRoot.querySelector(\"label[for='\".concat(id, \"']\"));\n        var text = label && label.innerText;\n        if (text) {\n            element.setAttribute('aria-label', text);\n        }\n    };\n    var templates = {\n        containerOuter: function (_a, dir, isSelectElement, isSelectOneElement, searchEnabled, passedElementType, labelId) {\n            var containerOuter = _a.classNames.containerOuter;\n            var div = document.createElement('div');\n            addClassesToElement(div, containerOuter);\n            div.dataset.type = passedElementType;\n            if (dir) {\n                div.dir = dir;\n            }\n            if (isSelectOneElement) {\n                div.tabIndex = 0;\n            }\n            if (isSelectElement) {\n                div.setAttribute('role', searchEnabled ? 'combobox' : 'listbox');\n                if (searchEnabled) {\n                    div.setAttribute('aria-autocomplete', 'list');\n                }\n                else if (!labelId) {\n                    addAriaLabel(this._docRoot, this.passedElement.element.id, div);\n                }\n                div.setAttribute('aria-haspopup', 'true');\n                div.setAttribute('aria-expanded', 'false');\n            }\n            if (labelId) {\n                div.setAttribute('aria-labelledby', labelId);\n            }\n            return div;\n        },\n        containerInner: function (_a) {\n            var containerInner = _a.classNames.containerInner;\n            var div = document.createElement('div');\n            addClassesToElement(div, containerInner);\n            return div;\n        },\n        itemList: function (_a, isSelectOneElement) {\n            var searchEnabled = _a.searchEnabled, _b = _a.classNames, list = _b.list, listSingle = _b.listSingle, listItems = _b.listItems;\n            var div = document.createElement('div');\n            addClassesToElement(div, list);\n            addClassesToElement(div, isSelectOneElement ? listSingle : listItems);\n            if (this._isSelectElement && searchEnabled) {\n                div.setAttribute('role', 'listbox');\n            }\n            return div;\n        },\n        placeholder: function (_a, value) {\n            var allowHTML = _a.allowHTML, placeholder = _a.classNames.placeholder;\n            var div = document.createElement('div');\n            addClassesToElement(div, placeholder);\n            setElementHtml(div, allowHTML, value);\n            return div;\n        },\n        item: function (_a, choice, removeItemButton) {\n            var allowHTML = _a.allowHTML, removeItemButtonAlignLeft = _a.removeItemButtonAlignLeft, removeItemIconText = _a.removeItemIconText, removeItemLabelText = _a.removeItemLabelText, _b = _a.classNames, item = _b.item, button = _b.button, highlightedState = _b.highlightedState, itemSelectable = _b.itemSelectable, placeholder = _b.placeholder;\n            var rawValue = unwrapStringForRaw(choice.value);\n            var div = document.createElement('div');\n            addClassesToElement(div, item);\n            if (choice.labelClass) {\n                var spanLabel = document.createElement('span');\n                setElementHtml(spanLabel, allowHTML, choice.label);\n                addClassesToElement(spanLabel, choice.labelClass);\n                div.appendChild(spanLabel);\n            }\n            else {\n                setElementHtml(div, allowHTML, choice.label);\n            }\n            div.dataset.item = '';\n            div.dataset.id = choice.id;\n            div.dataset.value = rawValue;\n            assignCustomProperties(div, choice, true);\n            if (choice.disabled || this.containerOuter.isDisabled) {\n                div.setAttribute('aria-disabled', 'true');\n            }\n            if (this._isSelectElement) {\n                div.setAttribute('aria-selected', 'true');\n                div.setAttribute('role', 'option');\n            }\n            if (choice.placeholder) {\n                addClassesToElement(div, placeholder);\n                div.dataset.placeholder = '';\n            }\n            addClassesToElement(div, choice.highlighted ? highlightedState : itemSelectable);\n            if (removeItemButton) {\n                if (choice.disabled) {\n                    removeClassesFromElement(div, itemSelectable);\n                }\n                div.dataset.deletable = '';\n                var removeButton = document.createElement('button');\n                removeButton.type = 'button';\n                addClassesToElement(removeButton, button);\n                var eventChoice = getChoiceForOutput(choice);\n                setElementHtml(removeButton, true, resolveNoticeFunction(removeItemIconText, choice.value, eventChoice));\n                var REMOVE_ITEM_LABEL = resolveNoticeFunction(removeItemLabelText, choice.value, eventChoice);\n                if (REMOVE_ITEM_LABEL) {\n                    removeButton.setAttribute('aria-label', REMOVE_ITEM_LABEL);\n                }\n                removeButton.dataset.button = '';\n                if (removeItemButtonAlignLeft) {\n                    div.insertAdjacentElement('afterbegin', removeButton);\n                }\n                else {\n                    div.appendChild(removeButton);\n                }\n            }\n            return div;\n        },\n        choiceList: function (_a, isSelectOneElement) {\n            var list = _a.classNames.list;\n            var div = document.createElement('div');\n            addClassesToElement(div, list);\n            if (!isSelectOneElement) {\n                div.setAttribute('aria-multiselectable', 'true');\n            }\n            div.setAttribute('role', 'listbox');\n            return div;\n        },\n        choiceGroup: function (_a, _b) {\n            var allowHTML = _a.allowHTML, _c = _a.classNames, group = _c.group, groupHeading = _c.groupHeading, itemDisabled = _c.itemDisabled;\n            var id = _b.id, label = _b.label, disabled = _b.disabled;\n            var rawLabel = unwrapStringForRaw(label);\n            var div = document.createElement('div');\n            addClassesToElement(div, group);\n            if (disabled) {\n                addClassesToElement(div, itemDisabled);\n            }\n            div.setAttribute('role', 'group');\n            div.dataset.group = '';\n            div.dataset.id = id;\n            div.dataset.value = rawLabel;\n            if (disabled) {\n                div.setAttribute('aria-disabled', 'true');\n            }\n            var heading = document.createElement('div');\n            addClassesToElement(heading, groupHeading);\n            setElementHtml(heading, allowHTML, label || '');\n            div.appendChild(heading);\n            return div;\n        },\n        choice: function (_a, choice, selectText, groupName) {\n            var allowHTML = _a.allowHTML, _b = _a.classNames, item = _b.item, itemChoice = _b.itemChoice, itemSelectable = _b.itemSelectable, selectedState = _b.selectedState, itemDisabled = _b.itemDisabled, description = _b.description, placeholder = _b.placeholder;\n            // eslint-disable-next-line prefer-destructuring\n            var label = choice.label;\n            var rawValue = unwrapStringForRaw(choice.value);\n            var div = document.createElement('div');\n            div.id = choice.elementId;\n            addClassesToElement(div, item);\n            addClassesToElement(div, itemChoice);\n            if (groupName && typeof label === 'string') {\n                label = escapeForTemplate(allowHTML, label);\n                label += \" (\".concat(groupName, \")\");\n                label = { trusted: label };\n            }\n            var describedBy = div;\n            if (choice.labelClass) {\n                var spanLabel = document.createElement('span');\n                setElementHtml(spanLabel, allowHTML, label);\n                addClassesToElement(spanLabel, choice.labelClass);\n                describedBy = spanLabel;\n                div.appendChild(spanLabel);\n            }\n            else {\n                setElementHtml(div, allowHTML, label);\n            }\n            if (choice.labelDescription) {\n                var descId = \"\".concat(choice.elementId, \"-description\");\n                describedBy.setAttribute('aria-describedby', descId);\n                var spanDesc = document.createElement('span');\n                setElementHtml(spanDesc, allowHTML, choice.labelDescription);\n                spanDesc.id = descId;\n                addClassesToElement(spanDesc, description);\n                div.appendChild(spanDesc);\n            }\n            if (choice.selected) {\n                addClassesToElement(div, selectedState);\n            }\n            if (choice.placeholder) {\n                addClassesToElement(div, placeholder);\n            }\n            div.setAttribute('role', choice.group ? 'treeitem' : 'option');\n            div.dataset.choice = '';\n            div.dataset.id = choice.id;\n            div.dataset.value = rawValue;\n            if (selectText) {\n                div.dataset.selectText = selectText;\n            }\n            if (choice.group) {\n                div.dataset.groupId = \"\".concat(choice.group.id);\n            }\n            assignCustomProperties(div, choice, false);\n            if (choice.disabled) {\n                addClassesToElement(div, itemDisabled);\n                div.dataset.choiceDisabled = '';\n                div.setAttribute('aria-disabled', 'true');\n            }\n            else {\n                addClassesToElement(div, itemSelectable);\n                div.dataset.choiceSelectable = '';\n                div.setAttribute('aria-selected', choice.selected ? 'true' : 'false');\n            }\n            return div;\n        },\n        input: function (_a, placeholderValue) {\n            var _b = _a.classNames, input = _b.input, inputCloned = _b.inputCloned, labelId = _a.labelId;\n            var inp = document.createElement('input');\n            inp.type = 'search';\n            addClassesToElement(inp, input);\n            addClassesToElement(inp, inputCloned);\n            inp.autocomplete = 'off';\n            inp.autocapitalize = 'off';\n            inp.spellcheck = false;\n            inp.setAttribute('aria-autocomplete', 'list');\n            if (placeholderValue) {\n                inp.setAttribute('aria-label', placeholderValue);\n            }\n            else if (!labelId) {\n                addAriaLabel(this._docRoot, this.passedElement.element.id, inp);\n            }\n            return inp;\n        },\n        dropdown: function (_a) {\n            var _b = _a.classNames, list = _b.list, listDropdown = _b.listDropdown;\n            var div = document.createElement('div');\n            addClassesToElement(div, list);\n            addClassesToElement(div, listDropdown);\n            div.setAttribute('aria-expanded', 'false');\n            return div;\n        },\n        notice: function (_a, innerHTML, type) {\n            var _b = _a.classNames, item = _b.item, itemChoice = _b.itemChoice, addChoice = _b.addChoice, noResults = _b.noResults, noChoices = _b.noChoices, noticeItem = _b.notice;\n            if (type === void 0) { type = NoticeTypes.generic; }\n            var notice = document.createElement('div');\n            setElementHtml(notice, true, innerHTML);\n            addClassesToElement(notice, item);\n            addClassesToElement(notice, itemChoice);\n            addClassesToElement(notice, noticeItem);\n            // eslint-disable-next-line default-case\n            switch (type) {\n                case NoticeTypes.addChoice:\n                    addClassesToElement(notice, addChoice);\n                    break;\n                case NoticeTypes.noResults:\n                    addClassesToElement(notice, noResults);\n                    break;\n                case NoticeTypes.noChoices:\n                    addClassesToElement(notice, noChoices);\n                    break;\n            }\n            if (type === NoticeTypes.addChoice) {\n                notice.dataset.choiceSelectable = '';\n                notice.dataset.choice = '';\n            }\n            return notice;\n        },\n        option: function (choice) {\n            // HtmlOptionElement's label value does not support HTML, so the avoid double escaping unwrap the untrusted string.\n            var labelValue = unwrapStringForRaw(choice.label);\n            var opt = new Option(labelValue, choice.value, false, choice.selected);\n            assignCustomProperties(opt, choice, true);\n            opt.disabled = choice.disabled;\n            if (choice.selected) {\n                opt.setAttribute('selected', '');\n            }\n            return opt;\n        },\n    };\n\n    /** @see {@link http://browserhacks.com/#hack-acea075d0ac6954f275a70023906050c} */\n    var IS_IE11 = '-ms-scroll-limit' in document.documentElement.style &&\n        '-ms-ime-align' in document.documentElement.style;\n    var USER_DEFAULTS = {};\n    var parseDataSetId = function (element) {\n        if (!element) {\n            return undefined;\n        }\n        return element.dataset.id ? parseInt(element.dataset.id, 10) : undefined;\n    };\n    var selectableChoiceIdentifier = '[data-choice-selectable]';\n    /**\n     * Choices\n     * @author Josh Johnson<josh@joshuajohnson.co.uk>\n     */\n    var Choices = /** @class */ (function () {\n        function Choices(element, userConfig) {\n            if (element === void 0) { element = '[data-choice]'; }\n            if (userConfig === void 0) { userConfig = {}; }\n            var _this = this;\n            this.initialisedOK = undefined;\n            this._hasNonChoicePlaceholder = false;\n            this._lastAddedChoiceId = 0;\n            this._lastAddedGroupId = 0;\n            var defaults = Choices.defaults;\n            this.config = __assign(__assign(__assign({}, defaults.allOptions), defaults.options), userConfig);\n            ObjectsInConfig.forEach(function (key) {\n                _this.config[key] = __assign(__assign(__assign({}, defaults.allOptions[key]), defaults.options[key]), userConfig[key]);\n            });\n            var config = this.config;\n            if (!config.silent) {\n                this._validateConfig();\n            }\n            var docRoot = config.shadowRoot || document.documentElement;\n            this._docRoot = docRoot;\n            var passedElement = typeof element === 'string' ? docRoot.querySelector(element) : element;\n            if (!passedElement ||\n                typeof passedElement !== 'object' ||\n                !(isHtmlInputElement(passedElement) || isHtmlSelectElement(passedElement))) {\n                if (!passedElement && typeof element === 'string') {\n                    throw TypeError(\"Selector \".concat(element, \" failed to find an element\"));\n                }\n                throw TypeError(\"Expected one of the following types text|select-one|select-multiple\");\n            }\n            var elementType = passedElement.type;\n            var isText = elementType === PassedElementTypes.Text;\n            if (isText || config.maxItemCount !== 1) {\n                config.singleModeForMultiSelect = false;\n            }\n            if (config.singleModeForMultiSelect) {\n                elementType = PassedElementTypes.SelectMultiple;\n            }\n            var isSelectOne = elementType === PassedElementTypes.SelectOne;\n            var isSelectMultiple = elementType === PassedElementTypes.SelectMultiple;\n            var isSelect = isSelectOne || isSelectMultiple;\n            this._elementType = elementType;\n            this._isTextElement = isText;\n            this._isSelectOneElement = isSelectOne;\n            this._isSelectMultipleElement = isSelectMultiple;\n            this._isSelectElement = isSelectOne || isSelectMultiple;\n            this._canAddUserChoices = (isText && config.addItems) || (isSelect && config.addChoices);\n            if (typeof config.renderSelectedChoices !== 'boolean') {\n                config.renderSelectedChoices = config.renderSelectedChoices === 'always' || isSelectOne;\n            }\n            if (config.closeDropdownOnSelect === 'auto') {\n                config.closeDropdownOnSelect = isText || isSelectOne || config.singleModeForMultiSelect;\n            }\n            else {\n                config.closeDropdownOnSelect = coerceBool(config.closeDropdownOnSelect);\n            }\n            if (config.placeholder) {\n                if (config.placeholderValue) {\n                    this._hasNonChoicePlaceholder = true;\n                }\n                else if (passedElement.dataset.placeholder) {\n                    this._hasNonChoicePlaceholder = true;\n                    config.placeholderValue = passedElement.dataset.placeholder;\n                }\n            }\n            if (userConfig.addItemFilter && typeof userConfig.addItemFilter !== 'function') {\n                var re = userConfig.addItemFilter instanceof RegExp ? userConfig.addItemFilter : new RegExp(userConfig.addItemFilter);\n                config.addItemFilter = re.test.bind(re);\n            }\n            if (this._isTextElement) {\n                this.passedElement = new WrappedInput({\n                    element: passedElement,\n                    classNames: config.classNames,\n                });\n            }\n            else {\n                var selectEl = passedElement;\n                this.passedElement = new WrappedSelect({\n                    element: selectEl,\n                    classNames: config.classNames,\n                    template: function (data) { return _this._templates.option(data); },\n                    extractPlaceholder: config.placeholder && !this._hasNonChoicePlaceholder,\n                });\n            }\n            this.initialised = false;\n            this._store = new Store(config);\n            this._currentValue = '';\n            config.searchEnabled = !isText && config.searchEnabled;\n            this._canSearch = config.searchEnabled;\n            this._isScrollingOnIe = false;\n            this._highlightPosition = 0;\n            this._wasTap = true;\n            this._placeholderValue = this._generatePlaceholderValue();\n            this._baseId = generateId(passedElement, 'choices-');\n            /**\n             * setting direction in cases where it's explicitly set on passedElement\n             * or when calculated direction is different from the document\n             */\n            this._direction = passedElement.dir;\n            if (!this._direction) {\n                var elementDirection = window.getComputedStyle(passedElement).direction;\n                var documentDirection = window.getComputedStyle(document.documentElement).direction;\n                if (elementDirection !== documentDirection) {\n                    this._direction = elementDirection;\n                }\n            }\n            this._idNames = {\n                itemChoice: 'item-choice',\n            };\n            this._templates = defaults.templates;\n            this._render = this._render.bind(this);\n            this._onFocus = this._onFocus.bind(this);\n            this._onBlur = this._onBlur.bind(this);\n            this._onKeyUp = this._onKeyUp.bind(this);\n            this._onKeyDown = this._onKeyDown.bind(this);\n            this._onInput = this._onInput.bind(this);\n            this._onClick = this._onClick.bind(this);\n            this._onTouchMove = this._onTouchMove.bind(this);\n            this._onTouchEnd = this._onTouchEnd.bind(this);\n            this._onMouseDown = this._onMouseDown.bind(this);\n            this._onMouseOver = this._onMouseOver.bind(this);\n            this._onFormReset = this._onFormReset.bind(this);\n            this._onSelectKey = this._onSelectKey.bind(this);\n            this._onEnterKey = this._onEnterKey.bind(this);\n            this._onEscapeKey = this._onEscapeKey.bind(this);\n            this._onDirectionKey = this._onDirectionKey.bind(this);\n            this._onDeleteKey = this._onDeleteKey.bind(this);\n            this._onChange = this._onChange.bind(this);\n            this._onInvalid = this._onInvalid.bind(this);\n            // If element has already been initialised with Choices, fail silently\n            if (this.passedElement.isActive) {\n                if (!config.silent) {\n                    console.warn('Trying to initialise Choices on element already initialised', { element: element });\n                }\n                this.initialised = true;\n                this.initialisedOK = false;\n                return;\n            }\n            // Let's go\n            this.init();\n            // preserve the selected item list after setup for form reset\n            this._initialItems = this._store.items.map(function (choice) { return choice.value; });\n        }\n        Object.defineProperty(Choices, \"defaults\", {\n            get: function () {\n                return Object.preventExtensions({\n                    get options() {\n                        return USER_DEFAULTS;\n                    },\n                    get allOptions() {\n                        return DEFAULT_CONFIG;\n                    },\n                    get templates() {\n                        return templates;\n                    },\n                });\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Choices.prototype.init = function () {\n            if (this.initialised || this.initialisedOK !== undefined) {\n                return;\n            }\n            this._searcher = getSearcher(this.config);\n            this._loadChoices();\n            this._createTemplates();\n            this._createElements();\n            this._createStructure();\n            if ((this._isTextElement && !this.config.addItems) ||\n                this.passedElement.element.hasAttribute('disabled') ||\n                !!this.passedElement.element.closest('fieldset:disabled')) {\n                this.disable();\n            }\n            else {\n                this.enable();\n                this._addEventListeners();\n            }\n            // should be triggered **after** disabled state to avoid additional re-draws\n            this._initStore();\n            this.initialised = true;\n            this.initialisedOK = true;\n            var callbackOnInit = this.config.callbackOnInit;\n            // Run callback if it is a function\n            if (typeof callbackOnInit === 'function') {\n                callbackOnInit.call(this);\n            }\n        };\n        Choices.prototype.destroy = function () {\n            if (!this.initialised) {\n                return;\n            }\n            this._removeEventListeners();\n            this.passedElement.reveal();\n            this.containerOuter.unwrap(this.passedElement.element);\n            this._store._listeners = []; // prevents select/input value being wiped\n            this.clearStore(false);\n            this._stopSearch();\n            this._templates = Choices.defaults.templates;\n            this.initialised = false;\n            this.initialisedOK = undefined;\n        };\n        Choices.prototype.enable = function () {\n            if (this.passedElement.isDisabled) {\n                this.passedElement.enable();\n            }\n            if (this.containerOuter.isDisabled) {\n                this._addEventListeners();\n                this.input.enable();\n                this.containerOuter.enable();\n            }\n            return this;\n        };\n        Choices.prototype.disable = function () {\n            if (!this.passedElement.isDisabled) {\n                this.passedElement.disable();\n            }\n            if (!this.containerOuter.isDisabled) {\n                this._removeEventListeners();\n                this.input.disable();\n                this.containerOuter.disable();\n            }\n            return this;\n        };\n        Choices.prototype.highlightItem = function (item, runEvent) {\n            if (runEvent === void 0) { runEvent = true; }\n            if (!item || !item.id) {\n                return this;\n            }\n            var choice = this._store.items.find(function (c) { return c.id === item.id; });\n            if (!choice || choice.highlighted) {\n                return this;\n            }\n            this._store.dispatch(highlightItem(choice, true));\n            if (runEvent) {\n                this.passedElement.triggerEvent(EventType.highlightItem, getChoiceForOutput(choice));\n            }\n            return this;\n        };\n        Choices.prototype.unhighlightItem = function (item, runEvent) {\n            if (runEvent === void 0) { runEvent = true; }\n            if (!item || !item.id) {\n                return this;\n            }\n            var choice = this._store.items.find(function (c) { return c.id === item.id; });\n            if (!choice || !choice.highlighted) {\n                return this;\n            }\n            this._store.dispatch(highlightItem(choice, false));\n            if (runEvent) {\n                this.passedElement.triggerEvent(EventType.unhighlightItem, getChoiceForOutput(choice));\n            }\n            return this;\n        };\n        Choices.prototype.highlightAll = function () {\n            var _this = this;\n            this._store.withTxn(function () {\n                _this._store.items.forEach(function (item) {\n                    if (!item.highlighted) {\n                        _this._store.dispatch(highlightItem(item, true));\n                        _this.passedElement.triggerEvent(EventType.highlightItem, getChoiceForOutput(item));\n                    }\n                });\n            });\n            return this;\n        };\n        Choices.prototype.unhighlightAll = function () {\n            var _this = this;\n            this._store.withTxn(function () {\n                _this._store.items.forEach(function (item) {\n                    if (item.highlighted) {\n                        _this._store.dispatch(highlightItem(item, false));\n                        _this.passedElement.triggerEvent(EventType.highlightItem, getChoiceForOutput(item));\n                    }\n                });\n            });\n            return this;\n        };\n        Choices.prototype.removeActiveItemsByValue = function (value) {\n            var _this = this;\n            this._store.withTxn(function () {\n                _this._store.items.filter(function (item) { return item.value === value; }).forEach(function (item) { return _this._removeItem(item); });\n            });\n            return this;\n        };\n        Choices.prototype.removeActiveItems = function (excludedId) {\n            var _this = this;\n            this._store.withTxn(function () {\n                _this._store.items.filter(function (_a) {\n                    var id = _a.id;\n                    return id !== excludedId;\n                }).forEach(function (item) { return _this._removeItem(item); });\n            });\n            return this;\n        };\n        Choices.prototype.removeHighlightedItems = function (runEvent) {\n            var _this = this;\n            if (runEvent === void 0) { runEvent = false; }\n            this._store.withTxn(function () {\n                _this._store.highlightedActiveItems.forEach(function (item) {\n                    _this._removeItem(item);\n                    // If this action was performed by the user\n                    // trigger the event\n                    if (runEvent) {\n                        _this._triggerChange(item.value);\n                    }\n                });\n            });\n            return this;\n        };\n        Choices.prototype.showDropdown = function (preventInputFocus) {\n            var _this = this;\n            if (this.dropdown.isActive) {\n                return this;\n            }\n            if (preventInputFocus === undefined) {\n                // eslint-disable-next-line no-param-reassign\n                preventInputFocus = !this._canSearch;\n            }\n            requestAnimationFrame(function () {\n                _this.dropdown.show();\n                var rect = _this.dropdown.element.getBoundingClientRect();\n                _this.containerOuter.open(rect.bottom, rect.height);\n                if (!preventInputFocus) {\n                    _this.input.focus();\n                }\n                _this.passedElement.triggerEvent(EventType.showDropdown);\n                var activeElement = _this.choiceList.element.querySelector(getClassNamesSelector(_this.config.classNames.selectedState));\n                if (activeElement !== null && !isScrolledIntoView(activeElement, _this.choiceList.element)) {\n                    // We use the native scrollIntoView function instead of choiceList.scrollToChildElement to avoid animated scroll.\n                    activeElement.scrollIntoView();\n                }\n            });\n            return this;\n        };\n        Choices.prototype.hideDropdown = function (preventInputBlur) {\n            var _this = this;\n            if (!this.dropdown.isActive) {\n                return this;\n            }\n            this._removeHighlightedChoices();\n            requestAnimationFrame(function () {\n                _this.dropdown.hide();\n                _this.containerOuter.close();\n                if (!preventInputBlur && _this._canSearch) {\n                    _this.input.removeActiveDescendant();\n                    _this.input.blur();\n                }\n                _this.passedElement.triggerEvent(EventType.hideDropdown);\n            });\n            return this;\n        };\n        Choices.prototype.getValue = function (valueOnly) {\n            var values = this._store.items.map(function (item) {\n                return (valueOnly ? item.value : getChoiceForOutput(item));\n            });\n            return this._isSelectOneElement || this.config.singleModeForMultiSelect ? values[0] : values;\n        };\n        Choices.prototype.setValue = function (items) {\n            var _this = this;\n            if (!this.initialisedOK) {\n                this._warnChoicesInitFailed('setValue');\n                return this;\n            }\n            this._store.withTxn(function () {\n                items.forEach(function (value) {\n                    if (value) {\n                        _this._addChoice(mapInputToChoice(value, false));\n                    }\n                });\n            });\n            // @todo integrate with Store\n            this._searcher.reset();\n            return this;\n        };\n        Choices.prototype.setChoiceByValue = function (value) {\n            var _this = this;\n            if (!this.initialisedOK) {\n                this._warnChoicesInitFailed('setChoiceByValue');\n                return this;\n            }\n            if (this._isTextElement) {\n                return this;\n            }\n            this._store.withTxn(function () {\n                // If only one value has been passed, convert to array\n                var choiceValue = Array.isArray(value) ? value : [value];\n                // Loop through each value and\n                choiceValue.forEach(function (val) { return _this._findAndSelectChoiceByValue(val); });\n                _this.unhighlightAll();\n            });\n            // @todo integrate with Store\n            this._searcher.reset();\n            return this;\n        };\n        /**\n         * Set choices of select input via an array of objects (or function that returns array of object or promise of it),\n         * a value field name and a label field name.\n         * This behaves the same as passing items via the choices option but can be called after initialising Choices.\n         * This can also be used to add groups of choices (see example 2); Optionally pass a true `replaceChoices` value to remove any existing choices.\n         * Optionally pass a `customProperties` object to add additional data to your choices (useful when searching/filtering etc).\n         *\n         * **Input types affected:** select-one, select-multiple\n         *\n         * @example\n         * ```js\n         * const example = new Choices(element);\n         *\n         * example.setChoices([\n         *   {value: 'One', label: 'Label One', disabled: true},\n         *   {value: 'Two', label: 'Label Two', selected: true},\n         *   {value: 'Three', label: 'Label Three'},\n         * ], 'value', 'label', false);\n         * ```\n         *\n         * @example\n         * ```js\n         * const example = new Choices(element);\n         *\n         * example.setChoices(async () => {\n         *   try {\n         *      const items = await fetch('/items');\n         *      return items.json()\n         *   } catch(err) {\n         *      console.error(err)\n         *   }\n         * });\n         * ```\n         *\n         * @example\n         * ```js\n         * const example = new Choices(element);\n         *\n         * example.setChoices([{\n         *   label: 'Group one',\n         *   id: 1,\n         *   disabled: false,\n         *   choices: [\n         *     {value: 'Child One', label: 'Child One', selected: true},\n         *     {value: 'Child Two', label: 'Child Two',  disabled: true},\n         *     {value: 'Child Three', label: 'Child Three'},\n         *   ]\n         * },\n         * {\n         *   label: 'Group two',\n         *   id: 2,\n         *   disabled: false,\n         *   choices: [\n         *     {value: 'Child Four', label: 'Child Four', disabled: true},\n         *     {value: 'Child Five', label: 'Child Five'},\n         *     {value: 'Child Six', label: 'Child Six', customProperties: {\n         *       description: 'Custom description about child six',\n         *       random: 'Another random custom property'\n         *     }},\n         *   ]\n         * }], 'value', 'label', false);\n         * ```\n         */\n        Choices.prototype.setChoices = function (choicesArrayOrFetcher, value, label, replaceChoices, clearSearchFlag, replaceItems) {\n            var _this = this;\n            if (choicesArrayOrFetcher === void 0) { choicesArrayOrFetcher = []; }\n            if (value === void 0) { value = 'value'; }\n            if (label === void 0) { label = 'label'; }\n            if (replaceChoices === void 0) { replaceChoices = false; }\n            if (clearSearchFlag === void 0) { clearSearchFlag = true; }\n            if (replaceItems === void 0) { replaceItems = false; }\n            if (!this.initialisedOK) {\n                this._warnChoicesInitFailed('setChoices');\n                return this;\n            }\n            if (!this._isSelectElement) {\n                throw new TypeError(\"setChoices can't be used with INPUT based Choices\");\n            }\n            if (typeof value !== 'string' || !value) {\n                throw new TypeError(\"value parameter must be a name of 'value' field in passed objects\");\n            }\n            if (typeof choicesArrayOrFetcher === 'function') {\n                // it's a choices fetcher function\n                var fetcher_1 = choicesArrayOrFetcher(this);\n                if (typeof Promise === 'function' && fetcher_1 instanceof Promise) {\n                    // that's a promise\n                    // eslint-disable-next-line no-promise-executor-return\n                    return new Promise(function (resolve) { return requestAnimationFrame(resolve); })\n                        .then(function () { return _this._handleLoadingState(true); })\n                        .then(function () { return fetcher_1; })\n                        .then(function (data) {\n                        return _this.setChoices(data, value, label, replaceChoices, clearSearchFlag, replaceItems);\n                    })\n                        .catch(function (err) {\n                        if (!_this.config.silent) {\n                            console.error(err);\n                        }\n                    })\n                        .then(function () { return _this._handleLoadingState(false); })\n                        .then(function () { return _this; });\n                }\n                // function returned something else than promise, let's check if it's an array of choices\n                if (!Array.isArray(fetcher_1)) {\n                    throw new TypeError(\".setChoices first argument function must return either array of choices or Promise, got: \".concat(typeof fetcher_1));\n                }\n                // recursion with results, it's sync and choices were cleared already\n                return this.setChoices(fetcher_1, value, label, false);\n            }\n            if (!Array.isArray(choicesArrayOrFetcher)) {\n                throw new TypeError(\".setChoices must be called either with array of choices with a function resulting into Promise of array of choices\");\n            }\n            this.containerOuter.removeLoadingState();\n            this._store.withTxn(function () {\n                if (clearSearchFlag) {\n                    _this._isSearching = false;\n                }\n                // Clear choices if needed\n                if (replaceChoices) {\n                    _this.clearChoices(true, replaceItems);\n                }\n                var isDefaultValue = value === 'value';\n                var isDefaultLabel = label === 'label';\n                choicesArrayOrFetcher.forEach(function (groupOrChoice) {\n                    if ('choices' in groupOrChoice) {\n                        var group = groupOrChoice;\n                        if (!isDefaultLabel) {\n                            group = __assign(__assign({}, group), { label: group[label] });\n                        }\n                        _this._addGroup(mapInputToChoice(group, true));\n                    }\n                    else {\n                        var choice = groupOrChoice;\n                        if (!isDefaultLabel || !isDefaultValue) {\n                            choice = __assign(__assign({}, choice), { value: choice[value], label: choice[label] });\n                        }\n                        var choiceFull = mapInputToChoice(choice, false);\n                        _this._addChoice(choiceFull);\n                        if (choiceFull.placeholder && !_this._hasNonChoicePlaceholder) {\n                            _this._placeholderValue = unwrapStringForEscaped(choiceFull.label);\n                        }\n                    }\n                });\n                _this.unhighlightAll();\n            });\n            // @todo integrate with Store\n            this._searcher.reset();\n            return this;\n        };\n        Choices.prototype.refresh = function (withEvents, selectFirstOption, deselectAll) {\n            var _this = this;\n            if (withEvents === void 0) { withEvents = false; }\n            if (selectFirstOption === void 0) { selectFirstOption = false; }\n            if (deselectAll === void 0) { deselectAll = false; }\n            if (!this._isSelectElement) {\n                if (!this.config.silent) {\n                    console.warn('refresh method can only be used on choices backed by a <select> element');\n                }\n                return this;\n            }\n            this._store.withTxn(function () {\n                var choicesFromOptions = _this.passedElement.optionsAsChoices();\n                // Build the list of items which require preserving\n                var existingItems = {};\n                if (!deselectAll) {\n                    _this._store.items.forEach(function (choice) {\n                        if (choice.id && choice.active && choice.selected) {\n                            existingItems[choice.value] = true;\n                        }\n                    });\n                }\n                _this.clearStore(false);\n                var updateChoice = function (choice) {\n                    if (deselectAll) {\n                        _this._store.dispatch(removeItem$1(choice));\n                    }\n                    else if (existingItems[choice.value]) {\n                        choice.selected = true;\n                    }\n                };\n                choicesFromOptions.forEach(function (groupOrChoice) {\n                    if ('choices' in groupOrChoice) {\n                        groupOrChoice.choices.forEach(updateChoice);\n                        return;\n                    }\n                    updateChoice(groupOrChoice);\n                });\n                /* @todo only generate add events for the added options instead of all\n                if (withEvents) {\n                  items.forEach((choice) => {\n                    if (existingItems[choice.value]) {\n                      this.passedElement.triggerEvent(\n                        EventType.removeItem,\n                        this._getChoiceForEvent(choice),\n                      );\n                    }\n                  });\n                }\n                */\n                // load new choices & items\n                _this._addPredefinedChoices(choicesFromOptions, selectFirstOption, withEvents);\n                // re-do search if required\n                if (_this._isSearching) {\n                    _this._searchChoices(_this.input.value);\n                }\n            });\n            return this;\n        };\n        Choices.prototype.removeChoice = function (value) {\n            var choice = this._store.choices.find(function (c) { return c.value === value; });\n            if (!choice) {\n                return this;\n            }\n            this._clearNotice();\n            this._store.dispatch(removeChoice(choice));\n            // @todo integrate with Store\n            this._searcher.reset();\n            if (choice.selected) {\n                this.passedElement.triggerEvent(EventType.removeItem, getChoiceForOutput(choice));\n            }\n            return this;\n        };\n        Choices.prototype.clearChoices = function (clearOptions, clearItems) {\n            var _this = this;\n            if (clearOptions === void 0) { clearOptions = true; }\n            if (clearItems === void 0) { clearItems = false; }\n            if (clearOptions) {\n                if (clearItems) {\n                    this.passedElement.element.replaceChildren('');\n                }\n                else {\n                    this.passedElement.element.querySelectorAll(':not([selected])').forEach(function (el) {\n                        el.remove();\n                    });\n                }\n            }\n            this.itemList.element.replaceChildren('');\n            this.choiceList.element.replaceChildren('');\n            this._clearNotice();\n            this._store.withTxn(function () {\n                var items = clearItems ? [] : _this._store.items;\n                _this._store.reset();\n                items.forEach(function (item) {\n                    _this._store.dispatch(addChoice(item));\n                    _this._store.dispatch(addItem(item));\n                });\n            });\n            // @todo integrate with Store\n            this._searcher.reset();\n            return this;\n        };\n        Choices.prototype.clearStore = function (clearOptions) {\n            if (clearOptions === void 0) { clearOptions = true; }\n            this.clearChoices(clearOptions, true);\n            this._stopSearch();\n            this._lastAddedChoiceId = 0;\n            this._lastAddedGroupId = 0;\n            return this;\n        };\n        Choices.prototype.clearInput = function () {\n            var shouldSetInputWidth = !this._isSelectOneElement;\n            this.input.clear(shouldSetInputWidth);\n            this._stopSearch();\n            return this;\n        };\n        Choices.prototype._validateConfig = function () {\n            var config = this.config;\n            var invalidConfigOptions = diff(config, DEFAULT_CONFIG);\n            if (invalidConfigOptions.length) {\n                console.warn('Unknown config option(s) passed', invalidConfigOptions.join(', '));\n            }\n            if (config.allowHTML && config.allowHtmlUserInput) {\n                if (config.addItems) {\n                    console.warn('Warning: allowHTML/allowHtmlUserInput/addItems all being true is strongly not recommended and may lead to XSS attacks');\n                }\n                if (config.addChoices) {\n                    console.warn('Warning: allowHTML/allowHtmlUserInput/addChoices all being true is strongly not recommended and may lead to XSS attacks');\n                }\n            }\n        };\n        Choices.prototype._render = function (changes) {\n            if (changes === void 0) { changes = { choices: true, groups: true, items: true }; }\n            if (this._store.inTxn()) {\n                return;\n            }\n            if (this._isSelectElement) {\n                if (changes.choices || changes.groups) {\n                    this._renderChoices();\n                }\n            }\n            if (changes.items) {\n                this._renderItems();\n            }\n        };\n        Choices.prototype._renderChoices = function () {\n            var _this = this;\n            if (!this._canAddItems()) {\n                return; // block rendering choices if the input limit is reached.\n            }\n            var _a = this, config = _a.config, isSearching = _a._isSearching;\n            var _b = this._store, activeGroups = _b.activeGroups, activeChoices = _b.activeChoices;\n            var renderLimit = isSearching ? config.searchResultLimit : config.renderChoiceLimit;\n            if (this._isSelectElement) {\n                var backingOptions = activeChoices.filter(function (choice) { return !choice.element; });\n                if (backingOptions.length) {\n                    this.passedElement.addOptions(backingOptions);\n                }\n            }\n            var fragment = document.createDocumentFragment();\n            var renderableChoices = function (choices) {\n                return choices.filter(function (choice) {\n                    return !choice.placeholder &&\n                        (isSearching\n                            ? (config.searchRenderSelectedChoices || !choice.selected) && !!choice.rank\n                            : config.renderSelectedChoices || !choice.selected);\n                });\n            };\n            var showLabel = config.appendGroupInSearch && isSearching;\n            var selectableChoices = false;\n            var highlightedEl = null;\n            var renderChoices = function (choices, withinGroup) {\n                if (isSearching) {\n                    // sortByRank is used to ensure stable sorting, as scores are non-unique\n                    // this additionally ensures fuseOptions.sortFn is not ignored\n                    choices.sort(sortByRank);\n                }\n                else if (config.shouldSort) {\n                    choices.sort(config.sorter);\n                }\n                var choiceLimit = choices.length;\n                choiceLimit = !withinGroup && renderLimit > 0 && choiceLimit > renderLimit ? renderLimit : choiceLimit;\n                choiceLimit--;\n                choices.every(function (choice, index) {\n                    // choiceEl being empty signals the contents has probably significantly changed\n                    var dropdownItem = choice.choiceEl ||\n                        _this._templates.choice(config, choice, config.itemSelectText, showLabel && choice.group ? choice.group.label : undefined);\n                    choice.choiceEl = dropdownItem;\n                    fragment.appendChild(dropdownItem);\n                    if (isSearching || !choice.selected) {\n                        selectableChoices = true;\n                    }\n                    else if (!highlightedEl) {\n                        highlightedEl = dropdownItem;\n                    }\n                    return index < choiceLimit;\n                });\n            };\n            if (activeChoices.length) {\n                if (config.resetScrollPosition) {\n                    requestAnimationFrame(function () { return _this.choiceList.scrollToTop(); });\n                }\n                if (!this._hasNonChoicePlaceholder && !isSearching && this._isSelectOneElement) {\n                    // If we have a placeholder choice along with groups\n                    renderChoices(activeChoices.filter(function (choice) { return choice.placeholder && !choice.group; }), false);\n                }\n                // If we have grouped options\n                if (activeGroups.length && !isSearching) {\n                    if (config.shouldSort) {\n                        activeGroups.sort(config.sorter);\n                    }\n                    // render Choices without group first, regardless of sort, otherwise they won't be distinguishable\n                    // from the last group\n                    renderChoices(activeChoices.filter(function (choice) { return !choice.placeholder && !choice.group; }), false);\n                    activeGroups.forEach(function (group) {\n                        var groupChoices = renderableChoices(group.choices);\n                        if (groupChoices.length) {\n                            if (group.label) {\n                                var dropdownGroup = group.groupEl || _this._templates.choiceGroup(_this.config, group);\n                                group.groupEl = dropdownGroup;\n                                dropdownGroup.remove();\n                                fragment.appendChild(dropdownGroup);\n                            }\n                            renderChoices(groupChoices, true);\n                        }\n                    });\n                }\n                else {\n                    renderChoices(renderableChoices(activeChoices), false);\n                }\n            }\n            if (!selectableChoices && (isSearching || !fragment.children.length || !config.renderSelectedChoices)) {\n                if (!this._notice) {\n                    this._notice = {\n                        text: resolveStringFunction(isSearching ? config.noResultsText : config.noChoicesText),\n                        type: isSearching ? NoticeTypes.noResults : NoticeTypes.noChoices,\n                    };\n                }\n                fragment.replaceChildren('');\n            }\n            this._renderNotice(fragment);\n            this.choiceList.element.replaceChildren(fragment);\n            this._highlightChoice(highlightedEl);\n        };\n        Choices.prototype._renderItems = function () {\n            var _this = this;\n            var items = this._store.items || [];\n            var itemList = this.itemList.element;\n            var config = this.config;\n            var fragment = document.createDocumentFragment();\n            var itemFromList = function (item) {\n                return itemList.querySelector(\"[data-item][data-id=\\\"\".concat(item.id, \"\\\"]\"));\n            };\n            var addItemToFragment = function (item) {\n                var el = item.itemEl;\n                if (el && el.parentElement) {\n                    return;\n                }\n                el = itemFromList(item) || _this._templates.item(config, item, config.removeItemButton);\n                item.itemEl = el;\n                fragment.appendChild(el);\n            };\n            // new items\n            items.forEach(addItemToFragment);\n            var addedItems = !!fragment.childNodes.length;\n            if (this._isSelectOneElement) {\n                var existingItems = itemList.children.length;\n                if (addedItems || existingItems > 1) {\n                    var placeholder = itemList.querySelector(getClassNamesSelector(config.classNames.placeholder));\n                    if (placeholder) {\n                        placeholder.remove();\n                    }\n                }\n                else if (!addedItems && !existingItems && this._placeholderValue) {\n                    addedItems = true;\n                    addItemToFragment(mapInputToChoice({\n                        selected: true,\n                        value: '',\n                        label: this._placeholderValue,\n                        placeholder: true,\n                    }, false));\n                }\n            }\n            if (addedItems) {\n                itemList.append(fragment);\n                if (config.shouldSortItems && !this._isSelectOneElement) {\n                    items.sort(config.sorter);\n                    // push sorting into the DOM\n                    items.forEach(function (item) {\n                        var el = itemFromList(item);\n                        if (el) {\n                            el.remove();\n                            fragment.append(el);\n                        }\n                    });\n                    itemList.append(fragment);\n                }\n            }\n            if (this._isTextElement) {\n                // Update the value of the hidden input\n                this.passedElement.value = items.map(function (_a) {\n                    var value = _a.value;\n                    return value;\n                }).join(config.delimiter);\n            }\n        };\n        Choices.prototype._displayNotice = function (text, type, openDropdown) {\n            if (openDropdown === void 0) { openDropdown = true; }\n            var oldNotice = this._notice;\n            if (oldNotice &&\n                ((oldNotice.type === type && oldNotice.text === text) ||\n                    (oldNotice.type === NoticeTypes.addChoice &&\n                        (type === NoticeTypes.noResults || type === NoticeTypes.noChoices)))) {\n                if (openDropdown) {\n                    this.showDropdown(true);\n                }\n                return;\n            }\n            this._clearNotice();\n            this._notice = text\n                ? {\n                    text: text,\n                    type: type,\n                }\n                : undefined;\n            this._renderNotice();\n            if (openDropdown && text) {\n                this.showDropdown(true);\n            }\n        };\n        Choices.prototype._clearNotice = function () {\n            if (!this._notice) {\n                return;\n            }\n            var noticeElement = this.choiceList.element.querySelector(getClassNamesSelector(this.config.classNames.notice));\n            if (noticeElement) {\n                noticeElement.remove();\n            }\n            this._notice = undefined;\n        };\n        Choices.prototype._renderNotice = function (fragment) {\n            var noticeConf = this._notice;\n            if (noticeConf) {\n                var notice = this._templates.notice(this.config, noticeConf.text, noticeConf.type);\n                if (fragment) {\n                    fragment.append(notice);\n                }\n                else {\n                    this.choiceList.prepend(notice);\n                }\n            }\n        };\n        /**\n         * @deprecated Use utils.getChoiceForOutput\n         */\n        // eslint-disable-next-line class-methods-use-this\n        Choices.prototype._getChoiceForOutput = function (choice, keyCode) {\n            return getChoiceForOutput(choice, keyCode);\n        };\n        Choices.prototype._triggerChange = function (value) {\n            if (value === undefined || value === null) {\n                return;\n            }\n            this.passedElement.triggerEvent(EventType.change, {\n                value: value,\n            });\n        };\n        Choices.prototype._handleButtonAction = function (element) {\n            var _this = this;\n            var items = this._store.items;\n            if (!items.length || !this.config.removeItems || !this.config.removeItemButton) {\n                return;\n            }\n            var id = element && parseDataSetId(element.closest('[data-id]'));\n            var itemToRemove = id && items.find(function (item) { return item.id === id; });\n            if (!itemToRemove) {\n                return;\n            }\n            this._store.withTxn(function () {\n                // Remove item associated with button\n                _this._removeItem(itemToRemove);\n                _this._triggerChange(itemToRemove.value);\n                if (_this._isSelectOneElement && !_this._hasNonChoicePlaceholder) {\n                    var placeholderChoice = (_this.config.shouldSort ? _this._store.choices.reverse() : _this._store.choices).find(function (choice) { return choice.placeholder; });\n                    if (placeholderChoice) {\n                        _this._addItem(placeholderChoice);\n                        _this.unhighlightAll();\n                        if (placeholderChoice.value) {\n                            _this._triggerChange(placeholderChoice.value);\n                        }\n                    }\n                }\n            });\n        };\n        Choices.prototype._handleItemAction = function (element, hasShiftKey) {\n            var _this = this;\n            if (hasShiftKey === void 0) { hasShiftKey = false; }\n            var items = this._store.items;\n            if (!items.length || !this.config.removeItems || this._isSelectOneElement) {\n                return;\n            }\n            var id = parseDataSetId(element);\n            if (!id) {\n                return;\n            }\n            // We only want to select one item with a click\n            // so we deselect any items that aren't the target\n            // unless shift is being pressed\n            items.forEach(function (item) {\n                if (item.id === id && !item.highlighted) {\n                    _this.highlightItem(item);\n                }\n                else if (!hasShiftKey && item.highlighted) {\n                    _this.unhighlightItem(item);\n                }\n            });\n            // Focus input as without focus, a user cannot do anything with a\n            // highlighted item\n            this.input.focus();\n        };\n        Choices.prototype._handleChoiceAction = function (element) {\n            var _this = this;\n            // If we are clicking on an option\n            var id = parseDataSetId(element);\n            var choice = id && this._store.getChoiceById(id);\n            if (!choice || choice.disabled) {\n                return false;\n            }\n            var hasActiveDropdown = this.dropdown.isActive;\n            if (!choice.selected) {\n                if (!this._canAddItems()) {\n                    return true; // causes _onEnterKey to early out\n                }\n                this._store.withTxn(function () {\n                    _this._addItem(choice, true, true);\n                    _this.clearInput();\n                    _this.unhighlightAll();\n                });\n                this._triggerChange(choice.value);\n            }\n            // We want to close the dropdown if we are dealing with a single select box\n            if (hasActiveDropdown && this.config.closeDropdownOnSelect) {\n                this.hideDropdown(true);\n                this.containerOuter.element.focus();\n            }\n            return true;\n        };\n        Choices.prototype._handleBackspace = function (items) {\n            var config = this.config;\n            if (!config.removeItems || !items.length) {\n                return;\n            }\n            var lastItem = items[items.length - 1];\n            var hasHighlightedItems = items.some(function (item) { return item.highlighted; });\n            // If editing the last item is allowed and there are not other selected items,\n            // we can edit the item value. Otherwise if we can remove items, remove all selected items\n            if (config.editItems && !hasHighlightedItems && lastItem) {\n                this.input.value = lastItem.value;\n                this.input.setWidth();\n                this._removeItem(lastItem);\n                this._triggerChange(lastItem.value);\n            }\n            else {\n                if (!hasHighlightedItems) {\n                    // Highlight last item if none already highlighted\n                    this.highlightItem(lastItem, false);\n                }\n                this.removeHighlightedItems(true);\n            }\n        };\n        Choices.prototype._loadChoices = function () {\n            var _a;\n            var _this = this;\n            var config = this.config;\n            if (this._isTextElement) {\n                // Assign preset items from passed object first\n                this._presetChoices = config.items.map(function (e) { return mapInputToChoice(e, false); });\n                // Add any values passed from attribute\n                if (this.passedElement.value) {\n                    var elementItems = this.passedElement.value\n                        .split(config.delimiter)\n                        .map(function (e) { return mapInputToChoice(e, false, _this.config.allowHtmlUserInput); });\n                    this._presetChoices = this._presetChoices.concat(elementItems);\n                }\n                this._presetChoices.forEach(function (choice) {\n                    choice.selected = true;\n                });\n            }\n            else if (this._isSelectElement) {\n                // Assign preset choices from passed object\n                this._presetChoices = config.choices.map(function (e) { return mapInputToChoice(e, true); });\n                // Create array of choices from option elements\n                var choicesFromOptions = this.passedElement.optionsAsChoices();\n                if (choicesFromOptions) {\n                    (_a = this._presetChoices).push.apply(_a, choicesFromOptions);\n                }\n            }\n        };\n        Choices.prototype._handleLoadingState = function (setLoading) {\n            if (setLoading === void 0) { setLoading = true; }\n            var el = this.itemList.element;\n            if (setLoading) {\n                this.disable();\n                this.containerOuter.addLoadingState();\n                if (this._isSelectOneElement) {\n                    el.replaceChildren(this._templates.placeholder(this.config, this.config.loadingText));\n                }\n                else {\n                    this.input.placeholder = this.config.loadingText;\n                }\n            }\n            else {\n                this.enable();\n                this.containerOuter.removeLoadingState();\n                if (this._isSelectOneElement) {\n                    el.replaceChildren('');\n                    this._render();\n                }\n                else {\n                    this.input.placeholder = this._placeholderValue || '';\n                }\n            }\n        };\n        Choices.prototype._handleSearch = function (value) {\n            if (!this.input.isFocussed) {\n                return;\n            }\n            // Check that we have a value to search and the input was an alphanumeric character\n            if (value !== null && typeof value !== 'undefined' && value.length >= this.config.searchFloor) {\n                var resultCount = this.config.searchChoices ? this._searchChoices(value) : 0;\n                if (resultCount !== null) {\n                    // Trigger search event\n                    this.passedElement.triggerEvent(EventType.search, {\n                        value: value,\n                        resultCount: resultCount,\n                    });\n                }\n            }\n            else if (this._store.choices.some(function (option) { return !option.active; })) {\n                this._stopSearch();\n            }\n        };\n        Choices.prototype._canAddItems = function () {\n            var config = this.config;\n            var maxItemCount = config.maxItemCount, maxItemText = config.maxItemText;\n            if (!config.singleModeForMultiSelect && maxItemCount > 0 && maxItemCount <= this._store.items.length) {\n                this.choiceList.element.replaceChildren('');\n                this._notice = undefined;\n                this._displayNotice(typeof maxItemText === 'function' ? maxItemText(maxItemCount) : maxItemText, NoticeTypes.addChoice);\n                return false;\n            }\n            if (this._notice && this._notice.type === NoticeTypes.addChoice) {\n                this._clearNotice();\n            }\n            return true;\n        };\n        Choices.prototype._canCreateItem = function (value) {\n            var config = this.config;\n            var canAddItem = true;\n            var notice = '';\n            if (canAddItem && typeof config.addItemFilter === 'function' && !config.addItemFilter(value)) {\n                canAddItem = false;\n                notice = resolveNoticeFunction(config.customAddItemText, value, undefined);\n            }\n            if (canAddItem) {\n                var foundChoice = this._store.choices.find(function (choice) { return config.valueComparer(choice.value, value); });\n                if (foundChoice) {\n                    if (this._isSelectElement) {\n                        // for exact matches, do not prompt to add it as a custom choice\n                        this._displayNotice('', NoticeTypes.addChoice);\n                        return false;\n                    }\n                    if (!config.duplicateItemsAllowed) {\n                        canAddItem = false;\n                        notice = resolveNoticeFunction(config.uniqueItemText, value, undefined);\n                    }\n                }\n            }\n            if (canAddItem) {\n                notice = resolveNoticeFunction(config.addItemText, value, undefined);\n            }\n            if (notice) {\n                this._displayNotice(notice, NoticeTypes.addChoice);\n            }\n            return canAddItem;\n        };\n        Choices.prototype._searchChoices = function (value) {\n            var newValue = value.trim().replace(/\\s{2,}/, ' ');\n            // signal input didn't change search\n            if (!newValue.length || newValue === this._currentValue) {\n                return null;\n            }\n            var searcher = this._searcher;\n            if (searcher.isEmptyIndex()) {\n                searcher.index(this._store.searchableChoices);\n            }\n            // If new value matches the desired length and is not the same as the current value with a space\n            var results = searcher.search(newValue);\n            this._currentValue = newValue;\n            this._highlightPosition = 0;\n            this._isSearching = true;\n            var notice = this._notice;\n            var noticeType = notice && notice.type;\n            if (noticeType !== NoticeTypes.addChoice) {\n                if (!results.length) {\n                    this._displayNotice(resolveStringFunction(this.config.noResultsText), NoticeTypes.noResults);\n                }\n                else {\n                    this._clearNotice();\n                }\n            }\n            this._store.dispatch(filterChoices(results));\n            return results.length;\n        };\n        Choices.prototype._stopSearch = function () {\n            if (this._isSearching) {\n                this._currentValue = '';\n                this._isSearching = false;\n                this._clearNotice();\n                this._store.dispatch(activateChoices(true));\n                this.passedElement.triggerEvent(EventType.search, {\n                    value: '',\n                    resultCount: 0,\n                });\n            }\n        };\n        Choices.prototype._addEventListeners = function () {\n            var documentElement = this._docRoot;\n            var outerElement = this.containerOuter.element;\n            var inputElement = this.input.element;\n            var passedElement = this.passedElement.element;\n            // capture events - can cancel event processing or propagation\n            documentElement.addEventListener('touchend', this._onTouchEnd, true);\n            outerElement.addEventListener('keydown', this._onKeyDown, true);\n            outerElement.addEventListener('mousedown', this._onMouseDown, true);\n            // passive events - doesn't call `preventDefault` or `stopPropagation`\n            documentElement.addEventListener('click', this._onClick, { passive: true });\n            documentElement.addEventListener('touchmove', this._onTouchMove, {\n                passive: true,\n            });\n            this.dropdown.element.addEventListener('mouseover', this._onMouseOver, {\n                passive: true,\n            });\n            if (this._isSelectOneElement) {\n                outerElement.addEventListener('focus', this._onFocus, {\n                    passive: true,\n                });\n                outerElement.addEventListener('blur', this._onBlur, {\n                    passive: true,\n                });\n            }\n            inputElement.addEventListener('keyup', this._onKeyUp, {\n                passive: true,\n            });\n            inputElement.addEventListener('input', this._onInput, {\n                passive: true,\n            });\n            inputElement.addEventListener('focus', this._onFocus, {\n                passive: true,\n            });\n            inputElement.addEventListener('blur', this._onBlur, {\n                passive: true,\n            });\n            if (inputElement.form) {\n                inputElement.form.addEventListener('reset', this._onFormReset, {\n                    passive: true,\n                });\n            }\n            if (passedElement.hasAttribute('required')) {\n                passedElement.addEventListener('change', this._onChange, {\n                    passive: true,\n                });\n                passedElement.addEventListener('invalid', this._onInvalid, {\n                    passive: true,\n                });\n            }\n            this.input.addEventListeners();\n        };\n        Choices.prototype._removeEventListeners = function () {\n            var documentElement = this._docRoot;\n            var outerElement = this.containerOuter.element;\n            var inputElement = this.input.element;\n            var passedElement = this.passedElement.element;\n            documentElement.removeEventListener('touchend', this._onTouchEnd, true);\n            outerElement.removeEventListener('keydown', this._onKeyDown, true);\n            outerElement.removeEventListener('mousedown', this._onMouseDown, true);\n            documentElement.removeEventListener('click', this._onClick);\n            documentElement.removeEventListener('touchmove', this._onTouchMove);\n            this.dropdown.element.removeEventListener('mouseover', this._onMouseOver);\n            if (this._isSelectOneElement) {\n                outerElement.removeEventListener('focus', this._onFocus);\n                outerElement.removeEventListener('blur', this._onBlur);\n            }\n            inputElement.removeEventListener('keyup', this._onKeyUp);\n            inputElement.removeEventListener('input', this._onInput);\n            inputElement.removeEventListener('focus', this._onFocus);\n            inputElement.removeEventListener('blur', this._onBlur);\n            if (inputElement.form) {\n                inputElement.form.removeEventListener('reset', this._onFormReset);\n            }\n            if (passedElement.hasAttribute('required')) {\n                passedElement.removeEventListener('change', this._onChange);\n                passedElement.removeEventListener('invalid', this._onInvalid);\n            }\n            this.input.removeEventListeners();\n        };\n        Choices.prototype._onKeyDown = function (event) {\n            var keyCode = event.keyCode;\n            var hasActiveDropdown = this.dropdown.isActive;\n            /*\n            See:\n            https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key\n            https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values\n            https://en.wikipedia.org/wiki/UTF-16#Code_points_from_U+010000_to_U+10FFFF - UTF-16 surrogate pairs\n            https://stackoverflow.com/a/70866532 - \"Unidentified\" for mobile\n            http://www.unicode.org/versions/Unicode5.2.0/ch16.pdf#G19635 - U+FFFF is reserved (Section 16.7)\n        \n            Logic: when a key event is sent, `event.key` represents its printable value _or_ one\n            of a large list of special values indicating meta keys/functionality. In addition,\n            key events for compose functionality contain a value of `Dead` when mid-composition.\n        \n            I can't quite verify it, but non-English IMEs may also be able to generate key codes\n            for code points in the surrogate-pair range, which could potentially be seen as having\n            key.length > 1. Since `Fn` is one of the special keys, we can't distinguish by that\n            alone.\n        \n            Here, key.length === 1 means we know for sure the input was printable and not a special\n            `key` value. When the length is greater than 1, it could be either a printable surrogate\n            pair or a special `key` value. We can tell the difference by checking if the _character\n            code_ value (not code point!) is in the \"surrogate pair\" range or not.\n        \n            We don't use .codePointAt because an invalid code point would return 65535, which wouldn't\n            pass the >= 0x10000 check we would otherwise use.\n        \n            > ...The Unicode Standard sets aside 66 noncharacter code points. The last two code points\n            > of each plane are noncharacters: U+FFFE and U+FFFF on the BMP...\n            */\n            var wasPrintableChar = event.key.length === 1 ||\n                (event.key.length === 2 && event.key.charCodeAt(0) >= 0xd800) ||\n                event.key === 'Unidentified';\n            /*\n              We do not show the dropdown if focusing out with esc or navigating through input fields.\n              An activated search can still be opened with any other key.\n             */\n            if (!this._isTextElement &&\n                !hasActiveDropdown &&\n                keyCode !== KeyCodeMap.ESC_KEY &&\n                keyCode !== KeyCodeMap.TAB_KEY &&\n                keyCode !== KeyCodeMap.SHIFT_KEY) {\n                this.showDropdown();\n                if (!this.input.isFocussed && wasPrintableChar) {\n                    /*\n                      We update the input value with the pressed key as\n                      the input was not focussed at the time of key press\n                      therefore does not have the value of the key.\n                    */\n                    this.input.value += event.key;\n                    // browsers interpret a space as pagedown\n                    if (event.key === ' ') {\n                        event.preventDefault();\n                    }\n                }\n            }\n            switch (keyCode) {\n                case KeyCodeMap.A_KEY:\n                    return this._onSelectKey(event, this.itemList.element.hasChildNodes());\n                case KeyCodeMap.ENTER_KEY:\n                    return this._onEnterKey(event, hasActiveDropdown);\n                case KeyCodeMap.ESC_KEY:\n                    return this._onEscapeKey(event, hasActiveDropdown);\n                case KeyCodeMap.UP_KEY:\n                case KeyCodeMap.PAGE_UP_KEY:\n                case KeyCodeMap.DOWN_KEY:\n                case KeyCodeMap.PAGE_DOWN_KEY:\n                    return this._onDirectionKey(event, hasActiveDropdown);\n                case KeyCodeMap.DELETE_KEY:\n                case KeyCodeMap.BACK_KEY:\n                    return this._onDeleteKey(event, this._store.items, this.input.isFocussed);\n            }\n        };\n        Choices.prototype._onKeyUp = function ( /* event: KeyboardEvent */) {\n            this._canSearch = this.config.searchEnabled;\n        };\n        Choices.prototype._onInput = function ( /* event: InputEvent */) {\n            var value = this.input.value;\n            if (!value) {\n                if (this._isTextElement) {\n                    this.hideDropdown(true);\n                }\n                else {\n                    this._stopSearch();\n                }\n                return;\n            }\n            if (!this._canAddItems()) {\n                return;\n            }\n            if (this._canSearch) {\n                // do the search even if the entered text can not be added\n                this._handleSearch(value);\n            }\n            if (!this._canAddUserChoices) {\n                return;\n            }\n            // determine if a notice needs to be displayed for why a search result can't be added\n            this._canCreateItem(value);\n            if (this._isSelectElement) {\n                this._highlightPosition = 0; // reset to select the notice and/or exact match\n                this._highlightChoice();\n            }\n        };\n        Choices.prototype._onSelectKey = function (event, hasItems) {\n            // If CTRL + A or CMD + A have been pressed and there are items to select\n            if ((event.ctrlKey || event.metaKey) && hasItems) {\n                this._canSearch = false;\n                var shouldHightlightAll = this.config.removeItems && !this.input.value && this.input.element === document.activeElement;\n                if (shouldHightlightAll) {\n                    this.highlightAll();\n                }\n            }\n        };\n        Choices.prototype._onEnterKey = function (event, hasActiveDropdown) {\n            var _this = this;\n            var value = this.input.value;\n            var target = event.target;\n            event.preventDefault();\n            if (target && target.hasAttribute('data-button')) {\n                this._handleButtonAction(target);\n                return;\n            }\n            if (!hasActiveDropdown) {\n                if (this._isSelectElement || this._notice) {\n                    this.showDropdown();\n                }\n                return;\n            }\n            var highlightedChoice = this.dropdown.element.querySelector(getClassNamesSelector(this.config.classNames.highlightedState));\n            if (highlightedChoice && this._handleChoiceAction(highlightedChoice)) {\n                return;\n            }\n            if (!target || !value) {\n                this.hideDropdown(true);\n                return;\n            }\n            if (!this._canAddItems()) {\n                return;\n            }\n            var addedItem = false;\n            this._store.withTxn(function () {\n                addedItem = _this._findAndSelectChoiceByValue(value, true);\n                if (!addedItem) {\n                    if (!_this._canAddUserChoices) {\n                        return;\n                    }\n                    if (!_this._canCreateItem(value)) {\n                        return;\n                    }\n                    _this._addChoice(mapInputToChoice(value, false, _this.config.allowHtmlUserInput), true, true);\n                    addedItem = true;\n                }\n                _this.clearInput();\n                _this.unhighlightAll();\n            });\n            if (!addedItem) {\n                return;\n            }\n            this._triggerChange(value);\n            if (this.config.closeDropdownOnSelect) {\n                this.hideDropdown(true);\n            }\n        };\n        Choices.prototype._onEscapeKey = function (event, hasActiveDropdown) {\n            if (hasActiveDropdown) {\n                event.stopPropagation();\n                this.hideDropdown(true);\n                this._stopSearch();\n                this.containerOuter.element.focus();\n            }\n        };\n        Choices.prototype._onDirectionKey = function (event, hasActiveDropdown) {\n            var keyCode = event.keyCode;\n            // If up or down key is pressed, traverse through options\n            if (hasActiveDropdown || this._isSelectOneElement) {\n                this.showDropdown();\n                this._canSearch = false;\n                var directionInt = keyCode === KeyCodeMap.DOWN_KEY || keyCode === KeyCodeMap.PAGE_DOWN_KEY ? 1 : -1;\n                var skipKey = event.metaKey || keyCode === KeyCodeMap.PAGE_DOWN_KEY || keyCode === KeyCodeMap.PAGE_UP_KEY;\n                var nextEl = void 0;\n                if (skipKey) {\n                    if (directionInt > 0) {\n                        nextEl = this.dropdown.element.querySelector(\"\".concat(selectableChoiceIdentifier, \":last-of-type\"));\n                    }\n                    else {\n                        nextEl = this.dropdown.element.querySelector(selectableChoiceIdentifier);\n                    }\n                }\n                else {\n                    var currentEl = this.dropdown.element.querySelector(getClassNamesSelector(this.config.classNames.highlightedState));\n                    if (currentEl) {\n                        nextEl = getAdjacentEl(currentEl, selectableChoiceIdentifier, directionInt);\n                    }\n                    else {\n                        nextEl = this.dropdown.element.querySelector(selectableChoiceIdentifier);\n                    }\n                }\n                if (nextEl) {\n                    // We prevent default to stop the cursor moving\n                    // when pressing the arrow\n                    if (!isScrolledIntoView(nextEl, this.choiceList.element, directionInt)) {\n                        this.choiceList.scrollToChildElement(nextEl, directionInt);\n                    }\n                    this._highlightChoice(nextEl);\n                }\n                // Prevent default to maintain cursor position whilst\n                // traversing dropdown options\n                event.preventDefault();\n            }\n        };\n        Choices.prototype._onDeleteKey = function (event, items, hasFocusedInput) {\n            // If backspace or delete key is pressed and the input has no value\n            if (!this._isSelectOneElement && !event.target.value && hasFocusedInput) {\n                this._handleBackspace(items);\n                event.preventDefault();\n            }\n        };\n        Choices.prototype._onTouchMove = function () {\n            if (this._wasTap) {\n                this._wasTap = false;\n            }\n        };\n        Choices.prototype._onTouchEnd = function (event) {\n            var target = (event || event.touches[0]).target;\n            var touchWasWithinContainer = this._wasTap && this.containerOuter.element.contains(target);\n            if (touchWasWithinContainer) {\n                var containerWasExactTarget = target === this.containerOuter.element || target === this.containerInner.element;\n                if (containerWasExactTarget) {\n                    if (this._isTextElement) {\n                        this.input.focus();\n                    }\n                    else if (this._isSelectMultipleElement) {\n                        this.showDropdown();\n                    }\n                }\n                // Prevents focus event firing\n                event.stopPropagation();\n            }\n            this._wasTap = true;\n        };\n        /**\n         * Handles mousedown event in capture mode for containetOuter.element\n         */\n        Choices.prototype._onMouseDown = function (event) {\n            var target = event.target;\n            if (!(target instanceof Element)) {\n                return;\n            }\n            // If we have our mouse down on the scrollbar and are on IE11...\n            if (IS_IE11 && this.choiceList.element.contains(target)) {\n                // check if click was on a scrollbar area\n                var firstChoice = this.choiceList.element.firstElementChild;\n                this._isScrollingOnIe =\n                    this._direction === 'ltr' ? event.offsetX >= firstChoice.offsetWidth : event.offsetX < firstChoice.offsetLeft;\n            }\n            if (target === this.input.element) {\n                return;\n            }\n            var item = target.closest('[data-button],[data-item],[data-choice]');\n            if (item instanceof HTMLElement) {\n                if ('button' in item.dataset) {\n                    this._handleButtonAction(item);\n                }\n                else if ('item' in item.dataset) {\n                    this._handleItemAction(item, event.shiftKey);\n                }\n                else if ('choice' in item.dataset) {\n                    this._handleChoiceAction(item);\n                }\n            }\n            event.preventDefault();\n        };\n        /**\n         * Handles mouseover event over this.dropdown\n         * @param {MouseEvent} event\n         */\n        Choices.prototype._onMouseOver = function (_a) {\n            var target = _a.target;\n            if (target instanceof HTMLElement && 'choice' in target.dataset) {\n                this._highlightChoice(target);\n            }\n        };\n        Choices.prototype._onClick = function (_a) {\n            var target = _a.target;\n            var containerOuter = this.containerOuter;\n            var clickWasWithinContainer = containerOuter.element.contains(target);\n            if (clickWasWithinContainer) {\n                if (!this.dropdown.isActive && !containerOuter.isDisabled) {\n                    if (this._isTextElement) {\n                        if (document.activeElement !== this.input.element) {\n                            this.input.focus();\n                        }\n                    }\n                    else {\n                        this.showDropdown();\n                        containerOuter.element.focus();\n                    }\n                }\n                else if (this._isSelectOneElement &&\n                    target !== this.input.element &&\n                    !this.dropdown.element.contains(target)) {\n                    this.hideDropdown();\n                }\n            }\n            else {\n                containerOuter.removeFocusState();\n                this.hideDropdown(true);\n                this.unhighlightAll();\n            }\n        };\n        Choices.prototype._onFocus = function (_a) {\n            var target = _a.target;\n            var containerOuter = this.containerOuter;\n            var focusWasWithinContainer = target && containerOuter.element.contains(target);\n            if (!focusWasWithinContainer) {\n                return;\n            }\n            var targetIsInput = target === this.input.element;\n            if (this._isTextElement) {\n                if (targetIsInput) {\n                    containerOuter.addFocusState();\n                }\n            }\n            else if (this._isSelectMultipleElement) {\n                if (targetIsInput) {\n                    this.showDropdown(true);\n                    // If element is a select box, the focused element is the container and the dropdown\n                    // isn't already open, focus and show dropdown\n                    containerOuter.addFocusState();\n                }\n            }\n            else {\n                containerOuter.addFocusState();\n                if (targetIsInput) {\n                    this.showDropdown(true);\n                }\n            }\n        };\n        Choices.prototype._onBlur = function (_a) {\n            var target = _a.target;\n            var containerOuter = this.containerOuter;\n            var blurWasWithinContainer = target && containerOuter.element.contains(target);\n            if (blurWasWithinContainer && !this._isScrollingOnIe) {\n                if (target === this.input.element) {\n                    containerOuter.removeFocusState();\n                    this.hideDropdown(true);\n                    if (this._isTextElement || this._isSelectMultipleElement) {\n                        this.unhighlightAll();\n                    }\n                }\n                else if (target === this.containerOuter.element) {\n                    // Remove the focus state when the past outerContainer was the target\n                    containerOuter.removeFocusState();\n                    // Also close the dropdown if search is disabled\n                    if (!this.config.searchEnabled) {\n                        this.hideDropdown(true);\n                    }\n                }\n            }\n            else {\n                // On IE11, clicking the scollbar blurs our input and thus\n                // closes the dropdown. To stop this, we refocus our input\n                // if we know we are on IE *and* are scrolling.\n                this._isScrollingOnIe = false;\n                this.input.element.focus();\n            }\n        };\n        Choices.prototype._onFormReset = function () {\n            var _this = this;\n            this._store.withTxn(function () {\n                _this.clearInput();\n                _this.hideDropdown();\n                _this.refresh(false, false, true);\n                if (_this._initialItems.length) {\n                    _this.setChoiceByValue(_this._initialItems);\n                }\n            });\n        };\n        Choices.prototype._onChange = function (event) {\n            if (!event.target.checkValidity()) {\n                return;\n            }\n            this.containerOuter.removeInvalidState();\n        };\n        Choices.prototype._onInvalid = function () {\n            this.containerOuter.addInvalidState();\n        };\n        /**\n         * Removes any highlighted choice options\n         */\n        Choices.prototype._removeHighlightedChoices = function () {\n            var highlightedState = this.config.classNames.highlightedState;\n            var highlightedChoices = Array.from(this.dropdown.element.querySelectorAll(getClassNamesSelector(highlightedState)));\n            // Remove any highlighted choices\n            highlightedChoices.forEach(function (choice) {\n                removeClassesFromElement(choice, highlightedState);\n                choice.setAttribute('aria-selected', 'false');\n            });\n        };\n        Choices.prototype._highlightChoice = function (el) {\n            if (el === void 0) { el = null; }\n            var choices = Array.from(this.dropdown.element.querySelectorAll(selectableChoiceIdentifier));\n            if (!choices.length) {\n                return;\n            }\n            var passedEl = el;\n            var highlightedState = this.config.classNames.highlightedState;\n            this._removeHighlightedChoices();\n            if (passedEl) {\n                this._highlightPosition = choices.indexOf(passedEl);\n            }\n            else {\n                // Highlight choice based on last known highlight location\n                if (choices.length > this._highlightPosition) {\n                    // If we have an option to highlight\n                    passedEl = choices[this._highlightPosition];\n                }\n                else {\n                    // Otherwise highlight the option before\n                    passedEl = choices[choices.length - 1];\n                }\n                if (!passedEl) {\n                    passedEl = choices[0];\n                }\n            }\n            addClassesToElement(passedEl, highlightedState);\n            passedEl.setAttribute('aria-selected', 'true');\n            this.passedElement.triggerEvent(EventType.highlightChoice, {\n                el: passedEl,\n            });\n            if (this.dropdown.isActive) {\n                // IE11 ignores aria-label and blocks virtual keyboard\n                // if aria-activedescendant is set without a dropdown\n                this.input.setActiveDescendant(passedEl.id);\n                this.containerOuter.setActiveDescendant(passedEl.id);\n            }\n        };\n        Choices.prototype._addItem = function (item, withEvents, userTriggered) {\n            if (withEvents === void 0) { withEvents = true; }\n            if (userTriggered === void 0) { userTriggered = false; }\n            if (!item.id) {\n                throw new TypeError('item.id must be set before _addItem is called for a choice/item');\n            }\n            if (this.config.singleModeForMultiSelect || this._isSelectOneElement) {\n                this.removeActiveItems(item.id);\n            }\n            this._store.dispatch(addItem(item));\n            if (withEvents) {\n                var eventChoice = getChoiceForOutput(item);\n                this.passedElement.triggerEvent(EventType.addItem, eventChoice);\n                if (userTriggered) {\n                    this.passedElement.triggerEvent(EventType.choice, eventChoice);\n                }\n            }\n        };\n        Choices.prototype._removeItem = function (item) {\n            if (!item.id) {\n                return;\n            }\n            this._store.dispatch(removeItem$1(item));\n            var notice = this._notice;\n            if (notice && notice.type === NoticeTypes.noChoices) {\n                this._clearNotice();\n            }\n            this.passedElement.triggerEvent(EventType.removeItem, getChoiceForOutput(item));\n        };\n        Choices.prototype._addChoice = function (choice, withEvents, userTriggered) {\n            if (withEvents === void 0) { withEvents = true; }\n            if (userTriggered === void 0) { userTriggered = false; }\n            if (choice.id) {\n                throw new TypeError('Can not re-add a choice which has already been added');\n            }\n            var config = this.config;\n            if (!config.duplicateItemsAllowed && this._store.choices.find(function (c) { return config.valueComparer(c.value, choice.value); })) {\n                return;\n            }\n            // Generate unique id, in-place update is required so chaining _addItem works as expected\n            this._lastAddedChoiceId++;\n            choice.id = this._lastAddedChoiceId;\n            choice.elementId = \"\".concat(this._baseId, \"-\").concat(this._idNames.itemChoice, \"-\").concat(choice.id);\n            var prependValue = config.prependValue, appendValue = config.appendValue;\n            if (prependValue) {\n                choice.value = prependValue + choice.value;\n            }\n            if (appendValue) {\n                choice.value += appendValue.toString();\n            }\n            if ((prependValue || appendValue) && choice.element) {\n                choice.element.value = choice.value;\n            }\n            this._clearNotice();\n            this._store.dispatch(addChoice(choice));\n            if (choice.selected) {\n                this._addItem(choice, withEvents, userTriggered);\n            }\n        };\n        Choices.prototype._addGroup = function (group, withEvents) {\n            var _this = this;\n            if (withEvents === void 0) { withEvents = true; }\n            if (group.id) {\n                throw new TypeError('Can not re-add a group which has already been added');\n            }\n            this._store.dispatch(addGroup(group));\n            if (!group.choices) {\n                return;\n            }\n            // add unique id for the group(s), and do not store the full list of choices in this group\n            this._lastAddedGroupId++;\n            group.id = this._lastAddedGroupId;\n            group.choices.forEach(function (item) {\n                item.group = group;\n                if (group.disabled) {\n                    item.disabled = true;\n                }\n                _this._addChoice(item, withEvents);\n            });\n        };\n        Choices.prototype._createTemplates = function () {\n            var _this = this;\n            var callbackOnCreateTemplates = this.config.callbackOnCreateTemplates;\n            var userTemplates = {};\n            if (typeof callbackOnCreateTemplates === 'function') {\n                userTemplates = callbackOnCreateTemplates.call(this, strToEl, escapeForTemplate, getClassNames);\n            }\n            var templating = {};\n            Object.keys(this._templates).forEach(function (name) {\n                if (name in userTemplates) {\n                    templating[name] = userTemplates[name].bind(_this);\n                }\n                else {\n                    templating[name] = _this._templates[name].bind(_this);\n                }\n            });\n            this._templates = templating;\n        };\n        Choices.prototype._createElements = function () {\n            var templating = this._templates;\n            var _a = this, config = _a.config, isSelectOneElement = _a._isSelectOneElement;\n            var position = config.position, classNames = config.classNames;\n            var elementType = this._elementType;\n            this.containerOuter = new Container({\n                element: templating.containerOuter(config, this._direction, this._isSelectElement, isSelectOneElement, config.searchEnabled, elementType, config.labelId),\n                classNames: classNames,\n                type: elementType,\n                position: position,\n            });\n            this.containerInner = new Container({\n                element: templating.containerInner(config),\n                classNames: classNames,\n                type: elementType,\n                position: position,\n            });\n            this.input = new Input({\n                element: templating.input(config, this._placeholderValue),\n                classNames: classNames,\n                type: elementType,\n                preventPaste: !config.paste,\n            });\n            this.choiceList = new List({\n                element: templating.choiceList(config, isSelectOneElement),\n            });\n            this.itemList = new List({\n                element: templating.itemList(config, isSelectOneElement),\n            });\n            this.dropdown = new Dropdown({\n                element: templating.dropdown(config),\n                classNames: classNames,\n                type: elementType,\n            });\n        };\n        Choices.prototype._createStructure = function () {\n            var _a = this, containerInner = _a.containerInner, containerOuter = _a.containerOuter, passedElement = _a.passedElement;\n            var dropdownElement = this.dropdown.element;\n            // Hide original element\n            passedElement.conceal();\n            // Wrap input in container preserving DOM ordering\n            containerInner.wrap(passedElement.element);\n            // Wrapper inner container with outer container\n            containerOuter.wrap(containerInner.element);\n            containerOuter.element.appendChild(containerInner.element);\n            containerOuter.element.appendChild(dropdownElement);\n            containerInner.element.appendChild(this.itemList.element);\n            dropdownElement.appendChild(this.choiceList.element);\n            if (this._isSelectOneElement) {\n                this.input.placeholder = this.config.searchPlaceholderValue || '';\n                if (this.config.searchEnabled) {\n                    dropdownElement.insertBefore(this.input.element, dropdownElement.firstChild);\n                }\n            }\n            else {\n                if (!this._isSelectMultipleElement || this.config.searchEnabled) {\n                    containerInner.element.appendChild(this.input.element);\n                }\n                if (this._placeholderValue) {\n                    this.input.placeholder = this._placeholderValue;\n                }\n                this.input.setWidth();\n            }\n            this._highlightPosition = 0;\n            this._isSearching = false;\n        };\n        Choices.prototype._initStore = function () {\n            var _this = this;\n            this._store.subscribe(this._render).withTxn(function () {\n                _this._addPredefinedChoices(_this._presetChoices, _this._isSelectOneElement && !_this._hasNonChoicePlaceholder, false);\n            });\n            if (!this._store.choices.length || (this._isSelectOneElement && this._hasNonChoicePlaceholder)) {\n                this._render();\n            }\n        };\n        Choices.prototype._addPredefinedChoices = function (choices, selectFirstOption, withEvents) {\n            var _this = this;\n            if (selectFirstOption === void 0) { selectFirstOption = false; }\n            if (withEvents === void 0) { withEvents = true; }\n            if (selectFirstOption) {\n                /**\n                 * If there is a selected choice already or the choice is not the first in\n                 * the array, add each choice normally.\n                 *\n                 * Otherwise we pre-select the first enabled choice in the array (\"select-one\" only)\n                 */\n                var noSelectedChoices = choices.findIndex(function (choice) { return choice.selected; }) === -1;\n                if (noSelectedChoices) {\n                    choices.some(function (choice) {\n                        if (choice.disabled || 'choices' in choice) {\n                            return false;\n                        }\n                        choice.selected = true;\n                        return true;\n                    });\n                }\n            }\n            choices.forEach(function (item) {\n                if ('choices' in item) {\n                    if (_this._isSelectElement) {\n                        _this._addGroup(item, withEvents);\n                    }\n                }\n                else {\n                    _this._addChoice(item, withEvents);\n                }\n            });\n        };\n        Choices.prototype._findAndSelectChoiceByValue = function (value, userTriggered) {\n            var _this = this;\n            if (userTriggered === void 0) { userTriggered = false; }\n            // Check 'value' property exists and the choice isn't already selected\n            var foundChoice = this._store.choices.find(function (choice) { return _this.config.valueComparer(choice.value, value); });\n            if (foundChoice && !foundChoice.disabled && !foundChoice.selected) {\n                this._addItem(foundChoice, true, userTriggered);\n                return true;\n            }\n            return false;\n        };\n        Choices.prototype._generatePlaceholderValue = function () {\n            var config = this.config;\n            if (!config.placeholder) {\n                return null;\n            }\n            if (this._hasNonChoicePlaceholder) {\n                return config.placeholderValue;\n            }\n            if (this._isSelectElement) {\n                var placeholderOption = this.passedElement.placeholderOption;\n                return placeholderOption ? placeholderOption.text : null;\n            }\n            return null;\n        };\n        Choices.prototype._warnChoicesInitFailed = function (caller) {\n            if (this.config.silent) {\n                return;\n            }\n            if (!this.initialised) {\n                throw new TypeError(\"\".concat(caller, \" called on a non-initialised instance of Choices\"));\n            }\n            else if (!this.initialisedOK) {\n                throw new TypeError(\"\".concat(caller, \" called for an element which has multiple instances of Choices initialised on it\"));\n            }\n        };\n        Choices.version = '11.2.1';\n        return Choices;\n    }());\n\n    return Choices;\n\n}));\n"
  },
  {
    "path": "public/assets/scripts/choices.search-kmp.mjs",
    "content": "/*! choices.js v11.2.1 | © 2026 Josh Johnson | https://github.com/Choices-js/Choices#readme */\n\n/******************************************************************************\nCopyright (c) Microsoft Corporation.\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\nPERFORMANCE OF THIS SOFTWARE.\n***************************************************************************** */\n/* global Reflect, Promise, SuppressedError, Symbol */\n\nvar extendStatics = function (d, b) {\n  extendStatics = Object.setPrototypeOf || {\n    __proto__: []\n  } instanceof Array && function (d, b) {\n    d.__proto__ = b;\n  } || function (d, b) {\n    for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p];\n  };\n  return extendStatics(d, b);\n};\nfunction __extends(d, b) {\n  if (typeof b !== \"function\" && b !== null) throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\n  extendStatics(d, b);\n  function __() {\n    this.constructor = d;\n  }\n  d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\n}\nvar __assign = function () {\n  __assign = Object.assign || function __assign(t) {\n    for (var s, i = 1, n = arguments.length; i < n; i++) {\n      s = arguments[i];\n      for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\n    }\n    return t;\n  };\n  return __assign.apply(this, arguments);\n};\ntypeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\n  var e = new Error(message);\n  return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\n};\n\nvar ActionType = {\n    ADD_CHOICE: 'ADD_CHOICE',\n    REMOVE_CHOICE: 'REMOVE_CHOICE',\n    FILTER_CHOICES: 'FILTER_CHOICES',\n    ACTIVATE_CHOICES: 'ACTIVATE_CHOICES',\n    CLEAR_CHOICES: 'CLEAR_CHOICES',\n    ADD_GROUP: 'ADD_GROUP',\n    ADD_ITEM: 'ADD_ITEM',\n    REMOVE_ITEM: 'REMOVE_ITEM',\n    HIGHLIGHT_ITEM: 'HIGHLIGHT_ITEM',\n};\n\nvar EventType = {\n    showDropdown: 'showDropdown',\n    hideDropdown: 'hideDropdown',\n    change: 'change',\n    choice: 'choice',\n    search: 'search',\n    addItem: 'addItem',\n    removeItem: 'removeItem',\n    highlightItem: 'highlightItem',\n    highlightChoice: 'highlightChoice',\n    unhighlightItem: 'unhighlightItem',\n};\n\nvar KeyCodeMap = {\n    TAB_KEY: 9,\n    SHIFT_KEY: 16,\n    BACK_KEY: 46,\n    DELETE_KEY: 8,\n    ENTER_KEY: 13,\n    A_KEY: 65,\n    ESC_KEY: 27,\n    UP_KEY: 38,\n    DOWN_KEY: 40,\n    PAGE_UP_KEY: 33,\n    PAGE_DOWN_KEY: 34,\n};\n\nvar ObjectsInConfig = ['fuseOptions', 'classNames'];\n\nvar PassedElementTypes = {\n    Text: 'text',\n    SelectOne: 'select-one',\n    SelectMultiple: 'select-multiple',\n};\n\nvar addChoice = function (choice) { return ({\n    type: ActionType.ADD_CHOICE,\n    choice: choice,\n}); };\nvar removeChoice = function (choice) { return ({\n    type: ActionType.REMOVE_CHOICE,\n    choice: choice,\n}); };\nvar filterChoices = function (results) { return ({\n    type: ActionType.FILTER_CHOICES,\n    results: results,\n}); };\nvar activateChoices = function (active) {\n    return ({\n        type: ActionType.ACTIVATE_CHOICES,\n        active: active,\n    });\n};\n\nvar addGroup = function (group) { return ({\n    type: ActionType.ADD_GROUP,\n    group: group,\n}); };\n\nvar addItem = function (item) { return ({\n    type: ActionType.ADD_ITEM,\n    item: item,\n}); };\nvar removeItem$1 = function (item) { return ({\n    type: ActionType.REMOVE_ITEM,\n    item: item,\n}); };\nvar highlightItem = function (item, highlighted) { return ({\n    type: ActionType.HIGHLIGHT_ITEM,\n    item: item,\n    highlighted: highlighted,\n}); };\n\nvar getRandomNumber = function (min, max) { return Math.floor(Math.random() * (max - min) + min); };\nvar generateChars = function (length) {\n    return Array.from({ length: length }, function () { return getRandomNumber(0, 36).toString(36); }).join('');\n};\nvar generateId = function (element, prefix) {\n    var id = element.id || (element.name && \"\".concat(element.name, \"-\").concat(generateChars(2))) || generateChars(4);\n    id = id.replace(/(:|\\.|\\[|\\]|,)/g, '');\n    id = \"\".concat(prefix, \"-\").concat(id);\n    return id;\n};\nvar getAdjacentEl = function (startEl, selector, direction) {\n    if (direction === void 0) { direction = 1; }\n    var prop = \"\".concat(direction > 0 ? 'next' : 'previous', \"ElementSibling\");\n    var sibling = startEl[prop];\n    while (sibling) {\n        if (sibling.matches(selector)) {\n            return sibling;\n        }\n        sibling = sibling[prop];\n    }\n    return null;\n};\nvar isScrolledIntoView = function (element, parent, direction) {\n    if (direction === void 0) { direction = 1; }\n    var isVisible;\n    if (direction > 0) {\n        // In view from bottom\n        isVisible = parent.scrollTop + parent.offsetHeight >= element.offsetTop + element.offsetHeight;\n    }\n    else {\n        // In view from top\n        isVisible = element.offsetTop >= parent.scrollTop;\n    }\n    return isVisible;\n};\nvar sanitise = function (value) {\n    if (typeof value !== 'string') {\n        if (value === null || value === undefined) {\n            return '';\n        }\n        if (typeof value === 'object') {\n            if ('raw' in value) {\n                return sanitise(value.raw);\n            }\n            if ('trusted' in value) {\n                return value.trusted;\n            }\n        }\n        return value;\n    }\n    return value\n        .replace(/&/g, '&amp;')\n        .replace(/>/g, '&gt;')\n        .replace(/</g, '&lt;')\n        .replace(/'/g, '&#039;')\n        .replace(/\"/g, '&quot;');\n};\nvar strToEl = (function () {\n    var tmpEl = document.createElement('div');\n    return function (str) {\n        tmpEl.innerHTML = str.trim();\n        var firstChild = tmpEl.children[0];\n        while (tmpEl.firstChild) {\n            tmpEl.removeChild(tmpEl.firstChild);\n        }\n        return firstChild;\n    };\n})();\nvar resolveStringFunction = function (fn) {\n    return typeof fn === 'function' ? fn() : fn;\n};\nvar unwrapStringForRaw = function (s) {\n    if (typeof s === 'string') {\n        return s;\n    }\n    if (typeof s === 'object') {\n        if ('trusted' in s) {\n            return s.trusted;\n        }\n        if ('raw' in s) {\n            return s.raw;\n        }\n    }\n    return '';\n};\nvar unwrapStringForEscaped = function (s) {\n    if (typeof s === 'string') {\n        return s;\n    }\n    if (typeof s === 'object') {\n        if ('escaped' in s) {\n            return s.escaped;\n        }\n        if ('trusted' in s) {\n            return s.trusted;\n        }\n    }\n    return '';\n};\nvar getChoiceForOutput = function (choice, keyCode) {\n    return {\n        id: choice.id,\n        highlighted: choice.highlighted,\n        labelClass: choice.labelClass,\n        labelDescription: unwrapStringForRaw(choice.labelDescription),\n        customProperties: choice.customProperties,\n        disabled: choice.disabled,\n        active: choice.active,\n        label: choice.label,\n        placeholder: choice.placeholder,\n        value: choice.value,\n        groupValue: choice.group ? choice.group.label : undefined,\n        element: choice.element,\n        keyCode: keyCode,\n    };\n};\nvar resolveNoticeFunction = function (fn, value, item) {\n    return typeof fn === 'function' ? fn(sanitise(value), unwrapStringForRaw(value), item) : fn;\n};\nvar escapeForTemplate = function (allowHTML, s) {\n    return allowHTML ? unwrapStringForEscaped(s) : sanitise(s);\n};\nvar setElementHtml = function (el, allowHtml, html) {\n    el.innerHTML = escapeForTemplate(allowHtml, html);\n};\nvar sortByAlpha = function (_a, _b) {\n    var value = _a.value, _c = _a.label, label = _c === void 0 ? value : _c;\n    var value2 = _b.value, _d = _b.label, label2 = _d === void 0 ? value2 : _d;\n    return unwrapStringForRaw(label).localeCompare(unwrapStringForRaw(label2), [], {\n        sensitivity: 'base',\n        ignorePunctuation: true,\n        numeric: true,\n    });\n};\nvar sortByRank = function (a, b) {\n    return a.rank - b.rank;\n};\nvar dispatchEvent = function (element, type, customArgs) {\n    if (customArgs === void 0) { customArgs = null; }\n    var event = new CustomEvent(type, {\n        detail: customArgs,\n        bubbles: true,\n        cancelable: true,\n    });\n    return element.dispatchEvent(event);\n};\n/**\n * Returns an array of keys present on the first but missing on the second object\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nvar diff = function (a, b) {\n    var aKeys = Object.keys(a).sort();\n    var bKeys = Object.keys(b).sort();\n    return aKeys.filter(function (i) { return bKeys.indexOf(i) < 0; });\n};\nvar getClassNames = function (ClassNames) {\n    return Array.isArray(ClassNames) ? ClassNames : [ClassNames];\n};\nvar getClassNamesSelector = function (option) {\n    if (option && Array.isArray(option)) {\n        return option\n            .map(function (item) {\n            return \".\".concat(item);\n        })\n            .join('');\n    }\n    return \".\".concat(option);\n};\nvar addClassesToElement = function (element, className) {\n    var _a;\n    (_a = element.classList).add.apply(_a, getClassNames(className));\n};\nvar removeClassesFromElement = function (element, className) {\n    var _a;\n    (_a = element.classList).remove.apply(_a, getClassNames(className));\n};\nvar parseCustomProperties = function (customProperties) {\n    if (typeof customProperties !== 'undefined') {\n        try {\n            return JSON.parse(customProperties);\n        }\n        catch (e) {\n            return customProperties;\n        }\n    }\n    return {};\n};\nvar updateClassList = function (item, add, remove) {\n    var itemEl = item.itemEl;\n    if (itemEl) {\n        removeClassesFromElement(itemEl, remove);\n        addClassesToElement(itemEl, add);\n    }\n};\n\nvar Dropdown = /** @class */ (function () {\n    function Dropdown(_a) {\n        var element = _a.element, type = _a.type, classNames = _a.classNames;\n        this.element = element;\n        this.classNames = classNames;\n        this.type = type;\n        this.isActive = false;\n    }\n    /**\n     * Show dropdown to user by adding active state class\n     */\n    Dropdown.prototype.show = function () {\n        addClassesToElement(this.element, this.classNames.activeState);\n        this.element.setAttribute('aria-expanded', 'true');\n        this.isActive = true;\n        return this;\n    };\n    /**\n     * Hide dropdown from user\n     */\n    Dropdown.prototype.hide = function () {\n        removeClassesFromElement(this.element, this.classNames.activeState);\n        this.element.setAttribute('aria-expanded', 'false');\n        this.isActive = false;\n        return this;\n    };\n    return Dropdown;\n}());\n\nvar Container = /** @class */ (function () {\n    function Container(_a) {\n        var element = _a.element, type = _a.type, classNames = _a.classNames, position = _a.position;\n        this.element = element;\n        this.classNames = classNames;\n        this.type = type;\n        this.position = position;\n        this.isOpen = false;\n        this.isFlipped = false;\n        this.isDisabled = false;\n        this.isLoading = false;\n    }\n    /**\n     * Determine whether container should be flipped based on passed\n     * dropdown position\n     */\n    Container.prototype.shouldFlip = function (dropdownPos, dropdownHeight) {\n        // If flip is enabled and the dropdown bottom position is\n        // greater than the window height flip the dropdown.\n        var shouldFlip = false;\n        if (this.position === 'auto') {\n            shouldFlip =\n                this.element.getBoundingClientRect().top - dropdownHeight >= 0 &&\n                    !window.matchMedia(\"(min-height: \".concat(dropdownPos + 1, \"px)\")).matches;\n        }\n        else if (this.position === 'top') {\n            shouldFlip = true;\n        }\n        return shouldFlip;\n    };\n    Container.prototype.setActiveDescendant = function (activeDescendantID) {\n        this.element.setAttribute('aria-activedescendant', activeDescendantID);\n    };\n    Container.prototype.removeActiveDescendant = function () {\n        this.element.removeAttribute('aria-activedescendant');\n    };\n    Container.prototype.open = function (dropdownPos, dropdownHeight) {\n        addClassesToElement(this.element, this.classNames.openState);\n        this.element.setAttribute('aria-expanded', 'true');\n        this.isOpen = true;\n        if (this.shouldFlip(dropdownPos, dropdownHeight)) {\n            addClassesToElement(this.element, this.classNames.flippedState);\n            this.isFlipped = true;\n        }\n    };\n    Container.prototype.close = function () {\n        removeClassesFromElement(this.element, this.classNames.openState);\n        this.element.setAttribute('aria-expanded', 'false');\n        this.removeActiveDescendant();\n        this.isOpen = false;\n        // A dropdown flips if it does not have space within the page\n        if (this.isFlipped) {\n            removeClassesFromElement(this.element, this.classNames.flippedState);\n            this.isFlipped = false;\n        }\n    };\n    Container.prototype.addFocusState = function () {\n        addClassesToElement(this.element, this.classNames.focusState);\n    };\n    Container.prototype.removeFocusState = function () {\n        removeClassesFromElement(this.element, this.classNames.focusState);\n    };\n    Container.prototype.addInvalidState = function () {\n        addClassesToElement(this.element, this.classNames.invalidState);\n    };\n    Container.prototype.removeInvalidState = function () {\n        removeClassesFromElement(this.element, this.classNames.invalidState);\n    };\n    Container.prototype.enable = function () {\n        removeClassesFromElement(this.element, this.classNames.disabledState);\n        this.element.removeAttribute('aria-disabled');\n        if (this.type === PassedElementTypes.SelectOne) {\n            this.element.setAttribute('tabindex', '0');\n        }\n        this.isDisabled = false;\n    };\n    Container.prototype.disable = function () {\n        addClassesToElement(this.element, this.classNames.disabledState);\n        this.element.setAttribute('aria-disabled', 'true');\n        if (this.type === PassedElementTypes.SelectOne) {\n            this.element.setAttribute('tabindex', '-1');\n        }\n        this.isDisabled = true;\n    };\n    Container.prototype.wrap = function (element) {\n        var el = this.element;\n        var parentNode = element.parentNode;\n        if (parentNode) {\n            if (element.nextSibling) {\n                parentNode.insertBefore(el, element.nextSibling);\n            }\n            else {\n                parentNode.appendChild(el);\n            }\n        }\n        el.appendChild(element);\n    };\n    Container.prototype.unwrap = function (element) {\n        var el = this.element;\n        var parentNode = el.parentNode;\n        if (parentNode) {\n            // Move passed element outside this element\n            parentNode.insertBefore(element, el);\n            // Remove this element\n            parentNode.removeChild(el);\n        }\n    };\n    Container.prototype.addLoadingState = function () {\n        addClassesToElement(this.element, this.classNames.loadingState);\n        this.element.setAttribute('aria-busy', 'true');\n        this.isLoading = true;\n    };\n    Container.prototype.removeLoadingState = function () {\n        removeClassesFromElement(this.element, this.classNames.loadingState);\n        this.element.removeAttribute('aria-busy');\n        this.isLoading = false;\n    };\n    return Container;\n}());\n\nvar Input = /** @class */ (function () {\n    function Input(_a) {\n        var element = _a.element, type = _a.type, classNames = _a.classNames, preventPaste = _a.preventPaste;\n        this.element = element;\n        this.type = type;\n        this.classNames = classNames;\n        this.preventPaste = preventPaste;\n        this.isFocussed = this.element.isEqualNode(document.activeElement);\n        this.isDisabled = element.disabled;\n        this._onPaste = this._onPaste.bind(this);\n        this._onInput = this._onInput.bind(this);\n        this._onFocus = this._onFocus.bind(this);\n        this._onBlur = this._onBlur.bind(this);\n    }\n    Object.defineProperty(Input.prototype, \"placeholder\", {\n        set: function (placeholder) {\n            this.element.placeholder = placeholder;\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(Input.prototype, \"value\", {\n        get: function () {\n            return this.element.value;\n        },\n        set: function (value) {\n            this.element.value = value;\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Input.prototype.addEventListeners = function () {\n        var el = this.element;\n        el.addEventListener('paste', this._onPaste);\n        el.addEventListener('input', this._onInput, {\n            passive: true,\n        });\n        el.addEventListener('focus', this._onFocus, {\n            passive: true,\n        });\n        el.addEventListener('blur', this._onBlur, {\n            passive: true,\n        });\n    };\n    Input.prototype.removeEventListeners = function () {\n        var el = this.element;\n        el.removeEventListener('input', this._onInput);\n        el.removeEventListener('paste', this._onPaste);\n        el.removeEventListener('focus', this._onFocus);\n        el.removeEventListener('blur', this._onBlur);\n    };\n    Input.prototype.enable = function () {\n        var el = this.element;\n        el.removeAttribute('disabled');\n        this.isDisabled = false;\n    };\n    Input.prototype.disable = function () {\n        var el = this.element;\n        el.setAttribute('disabled', '');\n        this.isDisabled = true;\n    };\n    Input.prototype.focus = function () {\n        if (!this.isFocussed) {\n            this.element.focus();\n        }\n    };\n    Input.prototype.blur = function () {\n        if (this.isFocussed) {\n            this.element.blur();\n        }\n    };\n    Input.prototype.clear = function (setWidth) {\n        if (setWidth === void 0) { setWidth = true; }\n        this.element.value = '';\n        if (setWidth) {\n            this.setWidth();\n        }\n        return this;\n    };\n    /**\n     * Set the correct input width based on placeholder\n     * value or input value\n     */\n    Input.prototype.setWidth = function () {\n        // Resize input to contents or placeholder\n        var element = this.element;\n        element.style.minWidth = \"\".concat(element.placeholder.length + 1, \"ch\");\n        element.style.width = \"\".concat(element.value.length + 1, \"ch\");\n    };\n    Input.prototype.setActiveDescendant = function (activeDescendantID) {\n        this.element.setAttribute('aria-activedescendant', activeDescendantID);\n    };\n    Input.prototype.removeActiveDescendant = function () {\n        this.element.removeAttribute('aria-activedescendant');\n    };\n    Input.prototype._onInput = function () {\n        if (this.type !== PassedElementTypes.SelectOne) {\n            this.setWidth();\n        }\n    };\n    Input.prototype._onPaste = function (event) {\n        if (this.preventPaste) {\n            event.preventDefault();\n        }\n    };\n    Input.prototype._onFocus = function () {\n        this.isFocussed = true;\n    };\n    Input.prototype._onBlur = function () {\n        this.isFocussed = false;\n    };\n    return Input;\n}());\n\nvar SCROLLING_SPEED = 4;\n\nvar List = /** @class */ (function () {\n    function List(_a) {\n        var element = _a.element;\n        this.element = element;\n        this.scrollPos = this.element.scrollTop;\n        this.height = this.element.offsetHeight;\n    }\n    List.prototype.prepend = function (node) {\n        var child = this.element.firstElementChild;\n        if (child) {\n            this.element.insertBefore(node, child);\n        }\n        else {\n            this.element.append(node);\n        }\n    };\n    List.prototype.scrollToTop = function () {\n        this.element.scrollTop = 0;\n    };\n    List.prototype.scrollToChildElement = function (element, direction) {\n        var _this = this;\n        if (!element) {\n            return;\n        }\n        var listHeight = this.element.offsetHeight;\n        // Scroll position of dropdown\n        var listScrollPosition = this.element.scrollTop + listHeight;\n        var elementHeight = element.offsetHeight;\n        // Distance from bottom of element to top of parent\n        var elementPos = element.offsetTop + elementHeight;\n        // Difference between the element and scroll position\n        var destination = direction > 0 ? this.element.scrollTop + elementPos - listScrollPosition : element.offsetTop;\n        requestAnimationFrame(function () {\n            _this._animateScroll(destination, direction);\n        });\n    };\n    List.prototype._scrollDown = function (scrollPos, strength, destination) {\n        var easing = (destination - scrollPos) / strength;\n        var distance = easing > 1 ? easing : 1;\n        this.element.scrollTop = scrollPos + distance;\n    };\n    List.prototype._scrollUp = function (scrollPos, strength, destination) {\n        var easing = (scrollPos - destination) / strength;\n        var distance = easing > 1 ? easing : 1;\n        this.element.scrollTop = scrollPos - distance;\n    };\n    List.prototype._animateScroll = function (destination, direction) {\n        var _this = this;\n        var strength = SCROLLING_SPEED;\n        var choiceListScrollTop = this.element.scrollTop;\n        var continueAnimation = false;\n        if (direction > 0) {\n            this._scrollDown(choiceListScrollTop, strength, destination);\n            if (choiceListScrollTop < destination) {\n                continueAnimation = true;\n            }\n        }\n        else {\n            this._scrollUp(choiceListScrollTop, strength, destination);\n            if (choiceListScrollTop > destination) {\n                continueAnimation = true;\n            }\n        }\n        if (continueAnimation) {\n            requestAnimationFrame(function () {\n                _this._animateScroll(destination, direction);\n            });\n        }\n    };\n    return List;\n}());\n\nvar WrappedElement = /** @class */ (function () {\n    function WrappedElement(_a) {\n        var element = _a.element, classNames = _a.classNames;\n        this.element = element;\n        this.classNames = classNames;\n        this.isDisabled = false;\n    }\n    Object.defineProperty(WrappedElement.prototype, \"isActive\", {\n        get: function () {\n            return this.element.dataset.choice === 'active';\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(WrappedElement.prototype, \"dir\", {\n        get: function () {\n            return this.element.dir;\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(WrappedElement.prototype, \"value\", {\n        get: function () {\n            return this.element.value;\n        },\n        set: function (value) {\n            this.element.setAttribute('value', value);\n            this.element.value = value;\n        },\n        enumerable: false,\n        configurable: true\n    });\n    WrappedElement.prototype.conceal = function () {\n        var el = this.element;\n        // Hide passed input\n        addClassesToElement(el, this.classNames.input);\n        el.hidden = true;\n        // Remove element from tab index\n        el.tabIndex = -1;\n        // Backup original styles if any\n        var origStyle = el.getAttribute('style');\n        if (origStyle) {\n            el.setAttribute('data-choice-orig-style', origStyle);\n        }\n        el.setAttribute('data-choice', 'active');\n    };\n    WrappedElement.prototype.reveal = function () {\n        var el = this.element;\n        // Reinstate passed element\n        removeClassesFromElement(el, this.classNames.input);\n        el.hidden = false;\n        el.removeAttribute('tabindex');\n        // Recover original styles if any\n        var origStyle = el.getAttribute('data-choice-orig-style');\n        if (origStyle) {\n            el.removeAttribute('data-choice-orig-style');\n            el.setAttribute('style', origStyle);\n        }\n        else {\n            el.removeAttribute('style');\n        }\n        el.removeAttribute('data-choice');\n    };\n    WrappedElement.prototype.enable = function () {\n        this.element.removeAttribute('disabled');\n        this.element.disabled = false;\n        this.isDisabled = false;\n    };\n    WrappedElement.prototype.disable = function () {\n        this.element.setAttribute('disabled', '');\n        this.element.disabled = true;\n        this.isDisabled = true;\n    };\n    WrappedElement.prototype.triggerEvent = function (eventType, data) {\n        dispatchEvent(this.element, eventType, data || {});\n    };\n    return WrappedElement;\n}());\n\nvar WrappedInput = /** @class */ (function (_super) {\n    __extends(WrappedInput, _super);\n    function WrappedInput() {\n        return _super !== null && _super.apply(this, arguments) || this;\n    }\n    return WrappedInput;\n}(WrappedElement));\n\nvar coerceBool = function (arg, defaultValue) {\n    if (defaultValue === void 0) { defaultValue = true; }\n    return typeof arg === 'undefined' ? defaultValue : !!arg;\n};\nvar stringToHtmlClass = function (input) {\n    if (typeof input === 'string') {\n        // eslint-disable-next-line no-param-reassign\n        input = input.split(' ').filter(function (s) { return s.length; });\n    }\n    if (Array.isArray(input) && input.length) {\n        return input;\n    }\n    return undefined;\n};\nvar mapInputToChoice = function (value, allowGroup, allowRawString) {\n    if (allowRawString === void 0) { allowRawString = true; }\n    if (typeof value === 'string') {\n        var sanitisedValue = sanitise(value);\n        var userValue = allowRawString || sanitisedValue === value ? value : { escaped: sanitisedValue, raw: value };\n        var result_1 = mapInputToChoice({\n            value: value,\n            label: userValue,\n            selected: true,\n        }, false);\n        return result_1;\n    }\n    var groupOrChoice = value;\n    if ('choices' in groupOrChoice) {\n        if (!allowGroup) {\n            // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/optgroup\n            throw new TypeError(\"optGroup is not allowed\");\n        }\n        var group = groupOrChoice;\n        var choices = group.choices.map(function (e) { return mapInputToChoice(e, false); });\n        var result_2 = {\n            id: 0, // actual ID will be assigned during _addGroup\n            label: unwrapStringForRaw(group.label) || group.value,\n            active: !!choices.length,\n            disabled: !!group.disabled,\n            choices: choices,\n        };\n        return result_2;\n    }\n    var choice = groupOrChoice;\n    var result = {\n        id: 0, // actual ID will be assigned during _addChoice\n        group: null, // actual group will be assigned during _addGroup but before _addChoice\n        score: 0, // used in search\n        rank: 0, // used in search, stable sort order\n        value: choice.value,\n        label: choice.label || choice.value,\n        active: coerceBool(choice.active),\n        selected: coerceBool(choice.selected, false),\n        disabled: coerceBool(choice.disabled, false),\n        placeholder: coerceBool(choice.placeholder, false),\n        highlighted: false,\n        labelClass: stringToHtmlClass(choice.labelClass),\n        labelDescription: choice.labelDescription,\n        customProperties: choice.customProperties,\n    };\n    return result;\n};\n\nvar isHtmlInputElement = function (e) { return e.tagName === 'INPUT'; };\nvar isHtmlSelectElement = function (e) { return e.tagName === 'SELECT'; };\nvar isHtmlOption = function (e) { return e.tagName === 'OPTION'; };\nvar isHtmlOptgroup = function (e) { return e.tagName === 'OPTGROUP'; };\n\nvar WrappedSelect = /** @class */ (function (_super) {\n    __extends(WrappedSelect, _super);\n    function WrappedSelect(_a) {\n        var element = _a.element, classNames = _a.classNames, template = _a.template, extractPlaceholder = _a.extractPlaceholder;\n        var _this = _super.call(this, { element: element, classNames: classNames }) || this;\n        _this.template = template;\n        _this.extractPlaceholder = extractPlaceholder;\n        return _this;\n    }\n    Object.defineProperty(WrappedSelect.prototype, \"placeholderOption\", {\n        get: function () {\n            return (this.element.querySelector('option[value=\"\"]') ||\n                // Backward compatibility layer for the non-standard placeholder attribute supported in older versions.\n                this.element.querySelector('option[placeholder]'));\n        },\n        enumerable: false,\n        configurable: true\n    });\n    WrappedSelect.prototype.addOptions = function (choices) {\n        var _this = this;\n        var fragment = document.createDocumentFragment();\n        choices.forEach(function (obj) {\n            var choice = obj;\n            if (choice.element) {\n                return;\n            }\n            var option = _this.template(choice);\n            fragment.appendChild(option);\n            choice.element = option;\n        });\n        this.element.appendChild(fragment);\n    };\n    WrappedSelect.prototype.optionsAsChoices = function () {\n        var _this = this;\n        var choices = [];\n        this.element.querySelectorAll(':scope > option, :scope > optgroup').forEach(function (e) {\n            if (isHtmlOption(e)) {\n                choices.push(_this._optionToChoice(e));\n            }\n            else if (isHtmlOptgroup(e)) {\n                choices.push(_this._optgroupToChoice(e));\n            }\n            // todo: hr as empty optgroup, requires displaying empty opt-groups to be useful\n        });\n        return choices;\n    };\n    // eslint-disable-next-line class-methods-use-this\n    WrappedSelect.prototype._optionToChoice = function (option) {\n        // option.value returns the label if there is no value attribute, which can break legacy placeholder attribute support\n        if (!option.hasAttribute('value') && option.hasAttribute('placeholder')) {\n            option.setAttribute('value', '');\n            option.value = '';\n        }\n        return {\n            id: 0,\n            group: null,\n            score: 0,\n            rank: 0,\n            value: option.value,\n            // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/option\n            // This attribute is text for the label indicating the meaning of the option. If the `label` attribute isn't defined, its value is that of the element text content (ie `innerText`).\n            label: option.label,\n            element: option,\n            active: true,\n            // this returns true if nothing is selected on initial load, which will break placeholder support\n            selected: this.extractPlaceholder ? option.selected : option.hasAttribute('selected'),\n            disabled: option.disabled,\n            highlighted: false,\n            placeholder: this.extractPlaceholder && (!option.value || option.hasAttribute('placeholder')),\n            labelClass: typeof option.dataset.labelClass !== 'undefined' ? stringToHtmlClass(option.dataset.labelClass) : undefined,\n            labelDescription: typeof option.dataset.labelDescription !== 'undefined'\n                ? { trusted: option.dataset.labelDescription }\n                : undefined,\n            customProperties: parseCustomProperties(option.dataset.customProperties),\n        };\n    };\n    WrappedSelect.prototype._optgroupToChoice = function (optgroup) {\n        var _this = this;\n        var options = optgroup.querySelectorAll('option');\n        var choices = Array.from(options).map(function (option) { return _this._optionToChoice(option); });\n        return {\n            id: 0,\n            label: optgroup.label || '',\n            element: optgroup,\n            active: !!choices.length,\n            disabled: optgroup.disabled,\n            choices: choices,\n        };\n    };\n    return WrappedSelect;\n}(WrappedElement));\n\nvar DEFAULT_CLASSNAMES = {\n    containerOuter: ['choices'],\n    containerInner: ['choices__inner'],\n    input: ['choices__input'],\n    inputCloned: ['choices__input--cloned'],\n    list: ['choices__list'],\n    listItems: ['choices__list--multiple'],\n    listSingle: ['choices__list--single'],\n    listDropdown: ['choices__list--dropdown'],\n    item: ['choices__item'],\n    itemSelectable: ['choices__item--selectable'],\n    itemDisabled: ['choices__item--disabled'],\n    itemChoice: ['choices__item--choice'],\n    description: ['choices__description'],\n    placeholder: ['choices__placeholder'],\n    group: ['choices__group'],\n    groupHeading: ['choices__heading'],\n    button: ['choices__button'],\n    activeState: ['is-active'],\n    focusState: ['is-focused'],\n    openState: ['is-open'],\n    disabledState: ['is-disabled'],\n    highlightedState: ['is-highlighted'],\n    selectedState: ['is-selected'],\n    flippedState: ['is-flipped'],\n    loadingState: ['is-loading'],\n    invalidState: ['is-invalid'],\n    notice: ['choices__notice'],\n    addChoice: ['choices__item--selectable', 'add-choice'],\n    noResults: ['has-no-results'],\n    noChoices: ['has-no-choices'],\n};\nvar DEFAULT_CONFIG = {\n    items: [],\n    choices: [],\n    silent: false,\n    renderChoiceLimit: -1,\n    maxItemCount: -1,\n    closeDropdownOnSelect: 'auto',\n    singleModeForMultiSelect: false,\n    addChoices: false,\n    addItems: true,\n    addItemFilter: function (value) { return !!value && value !== ''; },\n    removeItems: true,\n    removeItemButton: false,\n    removeItemButtonAlignLeft: false,\n    editItems: false,\n    allowHTML: false,\n    allowHtmlUserInput: false,\n    duplicateItemsAllowed: true,\n    delimiter: ',',\n    paste: true,\n    searchEnabled: true,\n    searchChoices: true,\n    searchDisabledChoices: false,\n    searchFloor: 1,\n    searchResultLimit: 4,\n    searchFields: ['label', 'value'],\n    position: 'auto',\n    resetScrollPosition: true,\n    shouldSort: true,\n    shouldSortItems: false,\n    sorter: sortByAlpha,\n    shadowRoot: null,\n    placeholder: true,\n    placeholderValue: null,\n    searchPlaceholderValue: null,\n    prependValue: null,\n    appendValue: null,\n    renderSelectedChoices: 'auto',\n    searchRenderSelectedChoices: true,\n    loadingText: 'Loading...',\n    noResultsText: 'No results found',\n    noChoicesText: 'No choices to choose from',\n    itemSelectText: 'Press to select',\n    uniqueItemText: 'Only unique values can be added',\n    customAddItemText: 'Only values matching specific conditions can be added',\n    addItemText: function (value) { return \"Press Enter to add <b>\\\"\".concat(value, \"\\\"</b>\"); },\n    removeItemIconText: function () { return \"Remove item\"; },\n    removeItemLabelText: function (value, _valueRaw, i) {\n        return \"Remove item: \".concat(i ? sanitise(i.label) : value);\n    },\n    maxItemText: function (maxItemCount) { return \"Only \".concat(maxItemCount, \" values can be added\"); },\n    valueComparer: function (value1, value2) { return value1 === value2; },\n    fuseOptions: {\n        includeScore: true,\n    },\n    labelId: '',\n    callbackOnInit: null,\n    callbackOnCreateTemplates: null,\n    classNames: DEFAULT_CLASSNAMES,\n    appendGroupInSearch: false,\n};\n\nvar removeItem = function (item) {\n    var itemEl = item.itemEl;\n    if (itemEl) {\n        itemEl.remove();\n        item.itemEl = undefined;\n    }\n};\nfunction items(s, action, context) {\n    var state = s;\n    var update = true;\n    switch (action.type) {\n        case ActionType.ADD_ITEM: {\n            action.item.selected = true;\n            var el = action.item.element;\n            if (el) {\n                el.selected = true;\n                el.setAttribute('selected', '');\n            }\n            state.push(action.item);\n            break;\n        }\n        case ActionType.REMOVE_ITEM: {\n            action.item.selected = false;\n            var el = action.item.element;\n            if (el) {\n                el.selected = false;\n                el.removeAttribute('selected');\n                // For a select-one, if all options are deselected, the first item is selected. To set a black value, select.value needs to be set\n                var select = el.parentElement;\n                if (select && isHtmlSelectElement(select) && select.type === PassedElementTypes.SelectOne) {\n                    select.value = '';\n                }\n            }\n            // this is mixing concerns, but this is *so much faster*\n            removeItem(action.item);\n            state = state.filter(function (choice) { return choice.id !== action.item.id; });\n            break;\n        }\n        case ActionType.REMOVE_CHOICE: {\n            removeItem(action.choice);\n            state = state.filter(function (item) { return item.id !== action.choice.id; });\n            break;\n        }\n        case ActionType.HIGHLIGHT_ITEM: {\n            var highlighted = action.highlighted;\n            var item = state.find(function (obj) { return obj.id === action.item.id; });\n            if (item && item.highlighted !== highlighted) {\n                item.highlighted = highlighted;\n                if (context) {\n                    updateClassList(item, highlighted ? context.classNames.highlightedState : context.classNames.selectedState, highlighted ? context.classNames.selectedState : context.classNames.highlightedState);\n                }\n            }\n            break;\n        }\n        default: {\n            update = false;\n            break;\n        }\n    }\n    return { state: state, update: update };\n}\n\nfunction groups(s, action) {\n    var state = s;\n    var update = true;\n    switch (action.type) {\n        case ActionType.ADD_GROUP: {\n            state.push(action.group);\n            break;\n        }\n        case ActionType.CLEAR_CHOICES: {\n            state = [];\n            break;\n        }\n        default: {\n            update = false;\n            break;\n        }\n    }\n    return { state: state, update: update };\n}\n\n/* eslint-disable */\nfunction choices(s, action, context) {\n    var state = s;\n    var update = true;\n    switch (action.type) {\n        case ActionType.ADD_CHOICE: {\n            state.push(action.choice);\n            break;\n        }\n        case ActionType.REMOVE_CHOICE: {\n            action.choice.choiceEl = undefined;\n            if (action.choice.group) {\n                action.choice.group.choices = action.choice.group.choices.filter(function (obj) { return obj.id !== action.choice.id; });\n            }\n            state = state.filter(function (obj) { return obj.id !== action.choice.id; });\n            break;\n        }\n        case ActionType.ADD_ITEM:\n        case ActionType.REMOVE_ITEM: {\n            action.item.choiceEl = undefined;\n            break;\n        }\n        case ActionType.FILTER_CHOICES: {\n            // avoid O(n^2) algorithm complexity when searching/filtering choices\n            var scoreLookup_1 = [];\n            action.results.forEach(function (result) {\n                scoreLookup_1[result.item.id] = result;\n            });\n            state.forEach(function (choice) {\n                var result = scoreLookup_1[choice.id];\n                if (result !== undefined) {\n                    choice.score = result.score;\n                    choice.rank = result.rank;\n                    choice.active = true;\n                }\n                else {\n                    choice.score = 0;\n                    choice.rank = 0;\n                    choice.active = false;\n                }\n                if (context && context.appendGroupInSearch) {\n                    choice.choiceEl = undefined;\n                }\n            });\n            break;\n        }\n        case ActionType.ACTIVATE_CHOICES: {\n            state.forEach(function (choice) {\n                choice.active = action.active;\n                if (context && context.appendGroupInSearch) {\n                    choice.choiceEl = undefined;\n                }\n            });\n            break;\n        }\n        case ActionType.CLEAR_CHOICES: {\n            state = [];\n            break;\n        }\n        default: {\n            update = false;\n            break;\n        }\n    }\n    return { state: state, update: update };\n}\n\nvar reducers = {\n    groups: groups,\n    items: items,\n    choices: choices,\n};\nvar Store = /** @class */ (function () {\n    function Store(context) {\n        this._state = this.defaultState;\n        this._listeners = [];\n        this._txn = 0;\n        this._context = context;\n    }\n    Object.defineProperty(Store.prototype, \"defaultState\", {\n        // eslint-disable-next-line class-methods-use-this\n        get: function () {\n            return {\n                groups: [],\n                items: [],\n                choices: [],\n            };\n        },\n        enumerable: false,\n        configurable: true\n    });\n    // eslint-disable-next-line class-methods-use-this\n    Store.prototype.changeSet = function (init) {\n        return {\n            groups: init,\n            items: init,\n            choices: init,\n        };\n    };\n    Store.prototype.reset = function () {\n        this._state = this.defaultState;\n        var changes = this.changeSet(true);\n        if (this._txn) {\n            this._changeSet = changes;\n        }\n        else {\n            this._listeners.forEach(function (l) { return l(changes); });\n        }\n    };\n    Store.prototype.subscribe = function (onChange) {\n        this._listeners.push(onChange);\n        return this;\n    };\n    Store.prototype.dispatch = function (action) {\n        var _this = this;\n        var state = this._state;\n        var hasChanges = false;\n        var changes = this._changeSet || this.changeSet(false);\n        Object.keys(reducers).forEach(function (key) {\n            var stateUpdate = reducers[key](state[key], action, _this._context);\n            if (stateUpdate.update) {\n                hasChanges = true;\n                changes[key] = true;\n                state[key] = stateUpdate.state;\n            }\n        });\n        if (hasChanges) {\n            if (this._txn) {\n                this._changeSet = changes;\n            }\n            else {\n                this._listeners.forEach(function (l) { return l(changes); });\n            }\n        }\n    };\n    Store.prototype.withTxn = function (func) {\n        this._txn++;\n        try {\n            func();\n        }\n        finally {\n            this._txn = Math.max(0, this._txn - 1);\n            if (!this._txn) {\n                var changeSet_1 = this._changeSet;\n                if (changeSet_1) {\n                    this._changeSet = undefined;\n                    this._listeners.forEach(function (l) { return l(changeSet_1); });\n                }\n            }\n        }\n    };\n    Object.defineProperty(Store.prototype, \"state\", {\n        /**\n         * Get store object\n         */\n        get: function () {\n            return this._state;\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(Store.prototype, \"items\", {\n        /**\n         * Get items from store\n         */\n        get: function () {\n            return this.state.items;\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(Store.prototype, \"highlightedActiveItems\", {\n        /**\n         * Get highlighted items from store\n         */\n        get: function () {\n            return this.items.filter(function (item) { return item.active && item.highlighted; });\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(Store.prototype, \"choices\", {\n        /**\n         * Get choices from store\n         */\n        get: function () {\n            return this.state.choices;\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(Store.prototype, \"activeChoices\", {\n        /**\n         * Get active choices from store\n         */\n        get: function () {\n            return this.choices.filter(function (choice) { return choice.active; });\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(Store.prototype, \"searchableChoices\", {\n        /**\n         * Get choices that can be searched (excluding placeholders or disabled choices)\n         */\n        get: function () {\n            var context = this._context;\n            return this.choices.filter(function (choice) { return !choice.placeholder && (context.searchDisabledChoices || !choice.disabled); });\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(Store.prototype, \"groups\", {\n        /**\n         * Get groups from store\n         */\n        get: function () {\n            return this.state.groups;\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(Store.prototype, \"activeGroups\", {\n        /**\n         * Get active groups from store\n         */\n        get: function () {\n            var _this = this;\n            return this.state.groups.filter(function (group) {\n                var isActive = group.active && !group.disabled;\n                var hasActiveOptions = _this.state.choices.some(function (choice) { return choice.active && !choice.disabled; });\n                return isActive && hasActiveOptions;\n            }, []);\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Store.prototype.inTxn = function () {\n        return this._txn > 0;\n    };\n    /**\n     * Get single choice by it's ID\n     */\n    Store.prototype.getChoiceById = function (id) {\n        return this.activeChoices.find(function (choice) { return choice.id === id; });\n    };\n    /**\n     * Get group by group id\n     */\n    Store.prototype.getGroupById = function (id) {\n        return this.groups.find(function (group) { return group.id === id; });\n    };\n    return Store;\n}());\n\nvar NoticeTypes = {\n    noChoices: 'no-choices',\n    noResults: 'no-results',\n    addChoice: 'add-choice',\n    generic: '',\n};\n\nfunction kmpSearch(pattern, text) {\n    if (pattern.length === 0) {\n        return 0; // Immediate match\n    }\n    // Compute longest suffix-prefix table\n    var lsp = [0]; // Base case\n    for (var i = 1; i < pattern.length; i++) {\n        var j_1 = lsp[i - 1]; // Start by assuming we're extending the previous LSP\n        while (j_1 > 0 && pattern.charAt(i) !== pattern.charAt(j_1)) {\n            j_1 = lsp[j_1 - 1];\n        }\n        if (pattern.charAt(i) === pattern.charAt(j_1)) {\n            j_1++;\n        }\n        lsp.push(j_1);\n    }\n    // Walk through text string\n    var j = 0; // Number of chars matched in pattern\n    for (var i = 0; i < text.length; i++) {\n        while (j > 0 && text.charAt(i) !== pattern.charAt(j)) {\n            j = lsp[j - 1]; // Fall back in the pattern\n        }\n        if (text.charAt(i) === pattern.charAt(j)) {\n            j++; // Next char matched, increment position\n            if (j === pattern.length) {\n                return i - (j - 1);\n            }\n        }\n    }\n    return -1; // Not found\n}\nvar SearchByKMP = /** @class */ (function () {\n    function SearchByKMP(config) {\n        this._haystack = [];\n        this._fields = config.searchFields;\n    }\n    SearchByKMP.prototype.index = function (data) {\n        this._haystack = data;\n    };\n    SearchByKMP.prototype.reset = function () {\n        this._haystack = [];\n    };\n    SearchByKMP.prototype.isEmptyIndex = function () {\n        return !this._haystack.length;\n    };\n    SearchByKMP.prototype.search = function (_needle) {\n        var fields = this._fields;\n        if (!fields || !fields.length || !_needle) {\n            return [];\n        }\n        var needle = _needle.toLowerCase();\n        var results = [];\n        var count = 0;\n        for (var i = 0, j = this._haystack.length; i < j; i++) {\n            var obj = this._haystack[i];\n            for (var k = 0, l = this._fields.length; k < l; k++) {\n                var field = this._fields[k];\n                if (field in obj && kmpSearch(needle, obj[field].toLowerCase()) !== -1) {\n                    results.push({\n                        item: obj,\n                        score: count,\n                        rank: count + 1,\n                    });\n                    count++;\n                    break;\n                }\n            }\n        }\n        return results;\n    };\n    return SearchByKMP;\n}());\n\nfunction getSearcher(config) {\n    {\n        return new SearchByKMP(config);\n    }\n}\n\n/**\n * Helpers to create HTML elements used by Choices\n * Can be overridden by providing `callbackOnCreateTemplates` option.\n * `Choices.defaults.templates` allows access to the default template methods from `callbackOnCreateTemplates`\n */\nvar isEmptyObject = function (obj) {\n    // eslint-disable-next-line no-restricted-syntax\n    for (var prop in obj) {\n        if (Object.prototype.hasOwnProperty.call(obj, prop)) {\n            return false;\n        }\n    }\n    return true;\n};\nvar assignCustomProperties = function (el, choice, withCustomProperties) {\n    var dataset = el.dataset;\n    var customProperties = choice.customProperties, labelClass = choice.labelClass, labelDescription = choice.labelDescription;\n    if (labelClass) {\n        dataset.labelClass = getClassNames(labelClass).join(' ');\n    }\n    if (labelDescription) {\n        dataset.labelDescription = unwrapStringForRaw(labelDescription);\n    }\n    if (withCustomProperties && customProperties) {\n        if (typeof customProperties === 'string') {\n            dataset.customProperties = customProperties;\n        }\n        else if (typeof customProperties === 'object' && !isEmptyObject(customProperties)) {\n            dataset.customProperties = JSON.stringify(customProperties);\n        }\n    }\n};\nvar addAriaLabel = function (docRoot, id, element) {\n    var label = id && docRoot.querySelector(\"label[for='\".concat(id, \"']\"));\n    var text = label && label.innerText;\n    if (text) {\n        element.setAttribute('aria-label', text);\n    }\n};\nvar templates = {\n    containerOuter: function (_a, dir, isSelectElement, isSelectOneElement, searchEnabled, passedElementType, labelId) {\n        var containerOuter = _a.classNames.containerOuter;\n        var div = document.createElement('div');\n        addClassesToElement(div, containerOuter);\n        div.dataset.type = passedElementType;\n        if (dir) {\n            div.dir = dir;\n        }\n        if (isSelectOneElement) {\n            div.tabIndex = 0;\n        }\n        if (isSelectElement) {\n            div.setAttribute('role', searchEnabled ? 'combobox' : 'listbox');\n            if (searchEnabled) {\n                div.setAttribute('aria-autocomplete', 'list');\n            }\n            else if (!labelId) {\n                addAriaLabel(this._docRoot, this.passedElement.element.id, div);\n            }\n            div.setAttribute('aria-haspopup', 'true');\n            div.setAttribute('aria-expanded', 'false');\n        }\n        if (labelId) {\n            div.setAttribute('aria-labelledby', labelId);\n        }\n        return div;\n    },\n    containerInner: function (_a) {\n        var containerInner = _a.classNames.containerInner;\n        var div = document.createElement('div');\n        addClassesToElement(div, containerInner);\n        return div;\n    },\n    itemList: function (_a, isSelectOneElement) {\n        var searchEnabled = _a.searchEnabled, _b = _a.classNames, list = _b.list, listSingle = _b.listSingle, listItems = _b.listItems;\n        var div = document.createElement('div');\n        addClassesToElement(div, list);\n        addClassesToElement(div, isSelectOneElement ? listSingle : listItems);\n        if (this._isSelectElement && searchEnabled) {\n            div.setAttribute('role', 'listbox');\n        }\n        return div;\n    },\n    placeholder: function (_a, value) {\n        var allowHTML = _a.allowHTML, placeholder = _a.classNames.placeholder;\n        var div = document.createElement('div');\n        addClassesToElement(div, placeholder);\n        setElementHtml(div, allowHTML, value);\n        return div;\n    },\n    item: function (_a, choice, removeItemButton) {\n        var allowHTML = _a.allowHTML, removeItemButtonAlignLeft = _a.removeItemButtonAlignLeft, removeItemIconText = _a.removeItemIconText, removeItemLabelText = _a.removeItemLabelText, _b = _a.classNames, item = _b.item, button = _b.button, highlightedState = _b.highlightedState, itemSelectable = _b.itemSelectable, placeholder = _b.placeholder;\n        var rawValue = unwrapStringForRaw(choice.value);\n        var div = document.createElement('div');\n        addClassesToElement(div, item);\n        if (choice.labelClass) {\n            var spanLabel = document.createElement('span');\n            setElementHtml(spanLabel, allowHTML, choice.label);\n            addClassesToElement(spanLabel, choice.labelClass);\n            div.appendChild(spanLabel);\n        }\n        else {\n            setElementHtml(div, allowHTML, choice.label);\n        }\n        div.dataset.item = '';\n        div.dataset.id = choice.id;\n        div.dataset.value = rawValue;\n        assignCustomProperties(div, choice, true);\n        if (choice.disabled || this.containerOuter.isDisabled) {\n            div.setAttribute('aria-disabled', 'true');\n        }\n        if (this._isSelectElement) {\n            div.setAttribute('aria-selected', 'true');\n            div.setAttribute('role', 'option');\n        }\n        if (choice.placeholder) {\n            addClassesToElement(div, placeholder);\n            div.dataset.placeholder = '';\n        }\n        addClassesToElement(div, choice.highlighted ? highlightedState : itemSelectable);\n        if (removeItemButton) {\n            if (choice.disabled) {\n                removeClassesFromElement(div, itemSelectable);\n            }\n            div.dataset.deletable = '';\n            var removeButton = document.createElement('button');\n            removeButton.type = 'button';\n            addClassesToElement(removeButton, button);\n            var eventChoice = getChoiceForOutput(choice);\n            setElementHtml(removeButton, true, resolveNoticeFunction(removeItemIconText, choice.value, eventChoice));\n            var REMOVE_ITEM_LABEL = resolveNoticeFunction(removeItemLabelText, choice.value, eventChoice);\n            if (REMOVE_ITEM_LABEL) {\n                removeButton.setAttribute('aria-label', REMOVE_ITEM_LABEL);\n            }\n            removeButton.dataset.button = '';\n            if (removeItemButtonAlignLeft) {\n                div.insertAdjacentElement('afterbegin', removeButton);\n            }\n            else {\n                div.appendChild(removeButton);\n            }\n        }\n        return div;\n    },\n    choiceList: function (_a, isSelectOneElement) {\n        var list = _a.classNames.list;\n        var div = document.createElement('div');\n        addClassesToElement(div, list);\n        if (!isSelectOneElement) {\n            div.setAttribute('aria-multiselectable', 'true');\n        }\n        div.setAttribute('role', 'listbox');\n        return div;\n    },\n    choiceGroup: function (_a, _b) {\n        var allowHTML = _a.allowHTML, _c = _a.classNames, group = _c.group, groupHeading = _c.groupHeading, itemDisabled = _c.itemDisabled;\n        var id = _b.id, label = _b.label, disabled = _b.disabled;\n        var rawLabel = unwrapStringForRaw(label);\n        var div = document.createElement('div');\n        addClassesToElement(div, group);\n        if (disabled) {\n            addClassesToElement(div, itemDisabled);\n        }\n        div.setAttribute('role', 'group');\n        div.dataset.group = '';\n        div.dataset.id = id;\n        div.dataset.value = rawLabel;\n        if (disabled) {\n            div.setAttribute('aria-disabled', 'true');\n        }\n        var heading = document.createElement('div');\n        addClassesToElement(heading, groupHeading);\n        setElementHtml(heading, allowHTML, label || '');\n        div.appendChild(heading);\n        return div;\n    },\n    choice: function (_a, choice, selectText, groupName) {\n        var allowHTML = _a.allowHTML, _b = _a.classNames, item = _b.item, itemChoice = _b.itemChoice, itemSelectable = _b.itemSelectable, selectedState = _b.selectedState, itemDisabled = _b.itemDisabled, description = _b.description, placeholder = _b.placeholder;\n        // eslint-disable-next-line prefer-destructuring\n        var label = choice.label;\n        var rawValue = unwrapStringForRaw(choice.value);\n        var div = document.createElement('div');\n        div.id = choice.elementId;\n        addClassesToElement(div, item);\n        addClassesToElement(div, itemChoice);\n        if (groupName && typeof label === 'string') {\n            label = escapeForTemplate(allowHTML, label);\n            label += \" (\".concat(groupName, \")\");\n            label = { trusted: label };\n        }\n        var describedBy = div;\n        if (choice.labelClass) {\n            var spanLabel = document.createElement('span');\n            setElementHtml(spanLabel, allowHTML, label);\n            addClassesToElement(spanLabel, choice.labelClass);\n            describedBy = spanLabel;\n            div.appendChild(spanLabel);\n        }\n        else {\n            setElementHtml(div, allowHTML, label);\n        }\n        if (choice.labelDescription) {\n            var descId = \"\".concat(choice.elementId, \"-description\");\n            describedBy.setAttribute('aria-describedby', descId);\n            var spanDesc = document.createElement('span');\n            setElementHtml(spanDesc, allowHTML, choice.labelDescription);\n            spanDesc.id = descId;\n            addClassesToElement(spanDesc, description);\n            div.appendChild(spanDesc);\n        }\n        if (choice.selected) {\n            addClassesToElement(div, selectedState);\n        }\n        if (choice.placeholder) {\n            addClassesToElement(div, placeholder);\n        }\n        div.setAttribute('role', choice.group ? 'treeitem' : 'option');\n        div.dataset.choice = '';\n        div.dataset.id = choice.id;\n        div.dataset.value = rawValue;\n        if (selectText) {\n            div.dataset.selectText = selectText;\n        }\n        if (choice.group) {\n            div.dataset.groupId = \"\".concat(choice.group.id);\n        }\n        assignCustomProperties(div, choice, false);\n        if (choice.disabled) {\n            addClassesToElement(div, itemDisabled);\n            div.dataset.choiceDisabled = '';\n            div.setAttribute('aria-disabled', 'true');\n        }\n        else {\n            addClassesToElement(div, itemSelectable);\n            div.dataset.choiceSelectable = '';\n            div.setAttribute('aria-selected', choice.selected ? 'true' : 'false');\n        }\n        return div;\n    },\n    input: function (_a, placeholderValue) {\n        var _b = _a.classNames, input = _b.input, inputCloned = _b.inputCloned, labelId = _a.labelId;\n        var inp = document.createElement('input');\n        inp.type = 'search';\n        addClassesToElement(inp, input);\n        addClassesToElement(inp, inputCloned);\n        inp.autocomplete = 'off';\n        inp.autocapitalize = 'off';\n        inp.spellcheck = false;\n        inp.setAttribute('aria-autocomplete', 'list');\n        if (placeholderValue) {\n            inp.setAttribute('aria-label', placeholderValue);\n        }\n        else if (!labelId) {\n            addAriaLabel(this._docRoot, this.passedElement.element.id, inp);\n        }\n        return inp;\n    },\n    dropdown: function (_a) {\n        var _b = _a.classNames, list = _b.list, listDropdown = _b.listDropdown;\n        var div = document.createElement('div');\n        addClassesToElement(div, list);\n        addClassesToElement(div, listDropdown);\n        div.setAttribute('aria-expanded', 'false');\n        return div;\n    },\n    notice: function (_a, innerHTML, type) {\n        var _b = _a.classNames, item = _b.item, itemChoice = _b.itemChoice, addChoice = _b.addChoice, noResults = _b.noResults, noChoices = _b.noChoices, noticeItem = _b.notice;\n        if (type === void 0) { type = NoticeTypes.generic; }\n        var notice = document.createElement('div');\n        setElementHtml(notice, true, innerHTML);\n        addClassesToElement(notice, item);\n        addClassesToElement(notice, itemChoice);\n        addClassesToElement(notice, noticeItem);\n        // eslint-disable-next-line default-case\n        switch (type) {\n            case NoticeTypes.addChoice:\n                addClassesToElement(notice, addChoice);\n                break;\n            case NoticeTypes.noResults:\n                addClassesToElement(notice, noResults);\n                break;\n            case NoticeTypes.noChoices:\n                addClassesToElement(notice, noChoices);\n                break;\n        }\n        if (type === NoticeTypes.addChoice) {\n            notice.dataset.choiceSelectable = '';\n            notice.dataset.choice = '';\n        }\n        return notice;\n    },\n    option: function (choice) {\n        // HtmlOptionElement's label value does not support HTML, so the avoid double escaping unwrap the untrusted string.\n        var labelValue = unwrapStringForRaw(choice.label);\n        var opt = new Option(labelValue, choice.value, false, choice.selected);\n        assignCustomProperties(opt, choice, true);\n        opt.disabled = choice.disabled;\n        if (choice.selected) {\n            opt.setAttribute('selected', '');\n        }\n        return opt;\n    },\n};\n\n/** @see {@link http://browserhacks.com/#hack-acea075d0ac6954f275a70023906050c} */\nvar IS_IE11 = '-ms-scroll-limit' in document.documentElement.style &&\n    '-ms-ime-align' in document.documentElement.style;\nvar USER_DEFAULTS = {};\nvar parseDataSetId = function (element) {\n    if (!element) {\n        return undefined;\n    }\n    return element.dataset.id ? parseInt(element.dataset.id, 10) : undefined;\n};\nvar selectableChoiceIdentifier = '[data-choice-selectable]';\n/**\n * Choices\n * @author Josh Johnson<josh@joshuajohnson.co.uk>\n */\nvar Choices = /** @class */ (function () {\n    function Choices(element, userConfig) {\n        if (element === void 0) { element = '[data-choice]'; }\n        if (userConfig === void 0) { userConfig = {}; }\n        var _this = this;\n        this.initialisedOK = undefined;\n        this._hasNonChoicePlaceholder = false;\n        this._lastAddedChoiceId = 0;\n        this._lastAddedGroupId = 0;\n        var defaults = Choices.defaults;\n        this.config = __assign(__assign(__assign({}, defaults.allOptions), defaults.options), userConfig);\n        ObjectsInConfig.forEach(function (key) {\n            _this.config[key] = __assign(__assign(__assign({}, defaults.allOptions[key]), defaults.options[key]), userConfig[key]);\n        });\n        var config = this.config;\n        if (!config.silent) {\n            this._validateConfig();\n        }\n        var docRoot = config.shadowRoot || document.documentElement;\n        this._docRoot = docRoot;\n        var passedElement = typeof element === 'string' ? docRoot.querySelector(element) : element;\n        if (!passedElement ||\n            typeof passedElement !== 'object' ||\n            !(isHtmlInputElement(passedElement) || isHtmlSelectElement(passedElement))) {\n            if (!passedElement && typeof element === 'string') {\n                throw TypeError(\"Selector \".concat(element, \" failed to find an element\"));\n            }\n            throw TypeError(\"Expected one of the following types text|select-one|select-multiple\");\n        }\n        var elementType = passedElement.type;\n        var isText = elementType === PassedElementTypes.Text;\n        if (isText || config.maxItemCount !== 1) {\n            config.singleModeForMultiSelect = false;\n        }\n        if (config.singleModeForMultiSelect) {\n            elementType = PassedElementTypes.SelectMultiple;\n        }\n        var isSelectOne = elementType === PassedElementTypes.SelectOne;\n        var isSelectMultiple = elementType === PassedElementTypes.SelectMultiple;\n        var isSelect = isSelectOne || isSelectMultiple;\n        this._elementType = elementType;\n        this._isTextElement = isText;\n        this._isSelectOneElement = isSelectOne;\n        this._isSelectMultipleElement = isSelectMultiple;\n        this._isSelectElement = isSelectOne || isSelectMultiple;\n        this._canAddUserChoices = (isText && config.addItems) || (isSelect && config.addChoices);\n        if (typeof config.renderSelectedChoices !== 'boolean') {\n            config.renderSelectedChoices = config.renderSelectedChoices === 'always' || isSelectOne;\n        }\n        if (config.closeDropdownOnSelect === 'auto') {\n            config.closeDropdownOnSelect = isText || isSelectOne || config.singleModeForMultiSelect;\n        }\n        else {\n            config.closeDropdownOnSelect = coerceBool(config.closeDropdownOnSelect);\n        }\n        if (config.placeholder) {\n            if (config.placeholderValue) {\n                this._hasNonChoicePlaceholder = true;\n            }\n            else if (passedElement.dataset.placeholder) {\n                this._hasNonChoicePlaceholder = true;\n                config.placeholderValue = passedElement.dataset.placeholder;\n            }\n        }\n        if (userConfig.addItemFilter && typeof userConfig.addItemFilter !== 'function') {\n            var re = userConfig.addItemFilter instanceof RegExp ? userConfig.addItemFilter : new RegExp(userConfig.addItemFilter);\n            config.addItemFilter = re.test.bind(re);\n        }\n        if (this._isTextElement) {\n            this.passedElement = new WrappedInput({\n                element: passedElement,\n                classNames: config.classNames,\n            });\n        }\n        else {\n            var selectEl = passedElement;\n            this.passedElement = new WrappedSelect({\n                element: selectEl,\n                classNames: config.classNames,\n                template: function (data) { return _this._templates.option(data); },\n                extractPlaceholder: config.placeholder && !this._hasNonChoicePlaceholder,\n            });\n        }\n        this.initialised = false;\n        this._store = new Store(config);\n        this._currentValue = '';\n        config.searchEnabled = !isText && config.searchEnabled;\n        this._canSearch = config.searchEnabled;\n        this._isScrollingOnIe = false;\n        this._highlightPosition = 0;\n        this._wasTap = true;\n        this._placeholderValue = this._generatePlaceholderValue();\n        this._baseId = generateId(passedElement, 'choices-');\n        /**\n         * setting direction in cases where it's explicitly set on passedElement\n         * or when calculated direction is different from the document\n         */\n        this._direction = passedElement.dir;\n        if (!this._direction) {\n            var elementDirection = window.getComputedStyle(passedElement).direction;\n            var documentDirection = window.getComputedStyle(document.documentElement).direction;\n            if (elementDirection !== documentDirection) {\n                this._direction = elementDirection;\n            }\n        }\n        this._idNames = {\n            itemChoice: 'item-choice',\n        };\n        this._templates = defaults.templates;\n        this._render = this._render.bind(this);\n        this._onFocus = this._onFocus.bind(this);\n        this._onBlur = this._onBlur.bind(this);\n        this._onKeyUp = this._onKeyUp.bind(this);\n        this._onKeyDown = this._onKeyDown.bind(this);\n        this._onInput = this._onInput.bind(this);\n        this._onClick = this._onClick.bind(this);\n        this._onTouchMove = this._onTouchMove.bind(this);\n        this._onTouchEnd = this._onTouchEnd.bind(this);\n        this._onMouseDown = this._onMouseDown.bind(this);\n        this._onMouseOver = this._onMouseOver.bind(this);\n        this._onFormReset = this._onFormReset.bind(this);\n        this._onSelectKey = this._onSelectKey.bind(this);\n        this._onEnterKey = this._onEnterKey.bind(this);\n        this._onEscapeKey = this._onEscapeKey.bind(this);\n        this._onDirectionKey = this._onDirectionKey.bind(this);\n        this._onDeleteKey = this._onDeleteKey.bind(this);\n        this._onChange = this._onChange.bind(this);\n        this._onInvalid = this._onInvalid.bind(this);\n        // If element has already been initialised with Choices, fail silently\n        if (this.passedElement.isActive) {\n            if (!config.silent) {\n                console.warn('Trying to initialise Choices on element already initialised', { element: element });\n            }\n            this.initialised = true;\n            this.initialisedOK = false;\n            return;\n        }\n        // Let's go\n        this.init();\n        // preserve the selected item list after setup for form reset\n        this._initialItems = this._store.items.map(function (choice) { return choice.value; });\n    }\n    Object.defineProperty(Choices, \"defaults\", {\n        get: function () {\n            return Object.preventExtensions({\n                get options() {\n                    return USER_DEFAULTS;\n                },\n                get allOptions() {\n                    return DEFAULT_CONFIG;\n                },\n                get templates() {\n                    return templates;\n                },\n            });\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Choices.prototype.init = function () {\n        if (this.initialised || this.initialisedOK !== undefined) {\n            return;\n        }\n        this._searcher = getSearcher(this.config);\n        this._loadChoices();\n        this._createTemplates();\n        this._createElements();\n        this._createStructure();\n        if ((this._isTextElement && !this.config.addItems) ||\n            this.passedElement.element.hasAttribute('disabled') ||\n            !!this.passedElement.element.closest('fieldset:disabled')) {\n            this.disable();\n        }\n        else {\n            this.enable();\n            this._addEventListeners();\n        }\n        // should be triggered **after** disabled state to avoid additional re-draws\n        this._initStore();\n        this.initialised = true;\n        this.initialisedOK = true;\n        var callbackOnInit = this.config.callbackOnInit;\n        // Run callback if it is a function\n        if (typeof callbackOnInit === 'function') {\n            callbackOnInit.call(this);\n        }\n    };\n    Choices.prototype.destroy = function () {\n        if (!this.initialised) {\n            return;\n        }\n        this._removeEventListeners();\n        this.passedElement.reveal();\n        this.containerOuter.unwrap(this.passedElement.element);\n        this._store._listeners = []; // prevents select/input value being wiped\n        this.clearStore(false);\n        this._stopSearch();\n        this._templates = Choices.defaults.templates;\n        this.initialised = false;\n        this.initialisedOK = undefined;\n    };\n    Choices.prototype.enable = function () {\n        if (this.passedElement.isDisabled) {\n            this.passedElement.enable();\n        }\n        if (this.containerOuter.isDisabled) {\n            this._addEventListeners();\n            this.input.enable();\n            this.containerOuter.enable();\n        }\n        return this;\n    };\n    Choices.prototype.disable = function () {\n        if (!this.passedElement.isDisabled) {\n            this.passedElement.disable();\n        }\n        if (!this.containerOuter.isDisabled) {\n            this._removeEventListeners();\n            this.input.disable();\n            this.containerOuter.disable();\n        }\n        return this;\n    };\n    Choices.prototype.highlightItem = function (item, runEvent) {\n        if (runEvent === void 0) { runEvent = true; }\n        if (!item || !item.id) {\n            return this;\n        }\n        var choice = this._store.items.find(function (c) { return c.id === item.id; });\n        if (!choice || choice.highlighted) {\n            return this;\n        }\n        this._store.dispatch(highlightItem(choice, true));\n        if (runEvent) {\n            this.passedElement.triggerEvent(EventType.highlightItem, getChoiceForOutput(choice));\n        }\n        return this;\n    };\n    Choices.prototype.unhighlightItem = function (item, runEvent) {\n        if (runEvent === void 0) { runEvent = true; }\n        if (!item || !item.id) {\n            return this;\n        }\n        var choice = this._store.items.find(function (c) { return c.id === item.id; });\n        if (!choice || !choice.highlighted) {\n            return this;\n        }\n        this._store.dispatch(highlightItem(choice, false));\n        if (runEvent) {\n            this.passedElement.triggerEvent(EventType.unhighlightItem, getChoiceForOutput(choice));\n        }\n        return this;\n    };\n    Choices.prototype.highlightAll = function () {\n        var _this = this;\n        this._store.withTxn(function () {\n            _this._store.items.forEach(function (item) {\n                if (!item.highlighted) {\n                    _this._store.dispatch(highlightItem(item, true));\n                    _this.passedElement.triggerEvent(EventType.highlightItem, getChoiceForOutput(item));\n                }\n            });\n        });\n        return this;\n    };\n    Choices.prototype.unhighlightAll = function () {\n        var _this = this;\n        this._store.withTxn(function () {\n            _this._store.items.forEach(function (item) {\n                if (item.highlighted) {\n                    _this._store.dispatch(highlightItem(item, false));\n                    _this.passedElement.triggerEvent(EventType.highlightItem, getChoiceForOutput(item));\n                }\n            });\n        });\n        return this;\n    };\n    Choices.prototype.removeActiveItemsByValue = function (value) {\n        var _this = this;\n        this._store.withTxn(function () {\n            _this._store.items.filter(function (item) { return item.value === value; }).forEach(function (item) { return _this._removeItem(item); });\n        });\n        return this;\n    };\n    Choices.prototype.removeActiveItems = function (excludedId) {\n        var _this = this;\n        this._store.withTxn(function () {\n            _this._store.items.filter(function (_a) {\n                var id = _a.id;\n                return id !== excludedId;\n            }).forEach(function (item) { return _this._removeItem(item); });\n        });\n        return this;\n    };\n    Choices.prototype.removeHighlightedItems = function (runEvent) {\n        var _this = this;\n        if (runEvent === void 0) { runEvent = false; }\n        this._store.withTxn(function () {\n            _this._store.highlightedActiveItems.forEach(function (item) {\n                _this._removeItem(item);\n                // If this action was performed by the user\n                // trigger the event\n                if (runEvent) {\n                    _this._triggerChange(item.value);\n                }\n            });\n        });\n        return this;\n    };\n    Choices.prototype.showDropdown = function (preventInputFocus) {\n        var _this = this;\n        if (this.dropdown.isActive) {\n            return this;\n        }\n        if (preventInputFocus === undefined) {\n            // eslint-disable-next-line no-param-reassign\n            preventInputFocus = !this._canSearch;\n        }\n        requestAnimationFrame(function () {\n            _this.dropdown.show();\n            var rect = _this.dropdown.element.getBoundingClientRect();\n            _this.containerOuter.open(rect.bottom, rect.height);\n            if (!preventInputFocus) {\n                _this.input.focus();\n            }\n            _this.passedElement.triggerEvent(EventType.showDropdown);\n            var activeElement = _this.choiceList.element.querySelector(getClassNamesSelector(_this.config.classNames.selectedState));\n            if (activeElement !== null && !isScrolledIntoView(activeElement, _this.choiceList.element)) {\n                // We use the native scrollIntoView function instead of choiceList.scrollToChildElement to avoid animated scroll.\n                activeElement.scrollIntoView();\n            }\n        });\n        return this;\n    };\n    Choices.prototype.hideDropdown = function (preventInputBlur) {\n        var _this = this;\n        if (!this.dropdown.isActive) {\n            return this;\n        }\n        this._removeHighlightedChoices();\n        requestAnimationFrame(function () {\n            _this.dropdown.hide();\n            _this.containerOuter.close();\n            if (!preventInputBlur && _this._canSearch) {\n                _this.input.removeActiveDescendant();\n                _this.input.blur();\n            }\n            _this.passedElement.triggerEvent(EventType.hideDropdown);\n        });\n        return this;\n    };\n    Choices.prototype.getValue = function (valueOnly) {\n        var values = this._store.items.map(function (item) {\n            return (valueOnly ? item.value : getChoiceForOutput(item));\n        });\n        return this._isSelectOneElement || this.config.singleModeForMultiSelect ? values[0] : values;\n    };\n    Choices.prototype.setValue = function (items) {\n        var _this = this;\n        if (!this.initialisedOK) {\n            this._warnChoicesInitFailed('setValue');\n            return this;\n        }\n        this._store.withTxn(function () {\n            items.forEach(function (value) {\n                if (value) {\n                    _this._addChoice(mapInputToChoice(value, false));\n                }\n            });\n        });\n        // @todo integrate with Store\n        this._searcher.reset();\n        return this;\n    };\n    Choices.prototype.setChoiceByValue = function (value) {\n        var _this = this;\n        if (!this.initialisedOK) {\n            this._warnChoicesInitFailed('setChoiceByValue');\n            return this;\n        }\n        if (this._isTextElement) {\n            return this;\n        }\n        this._store.withTxn(function () {\n            // If only one value has been passed, convert to array\n            var choiceValue = Array.isArray(value) ? value : [value];\n            // Loop through each value and\n            choiceValue.forEach(function (val) { return _this._findAndSelectChoiceByValue(val); });\n            _this.unhighlightAll();\n        });\n        // @todo integrate with Store\n        this._searcher.reset();\n        return this;\n    };\n    /**\n     * Set choices of select input via an array of objects (or function that returns array of object or promise of it),\n     * a value field name and a label field name.\n     * This behaves the same as passing items via the choices option but can be called after initialising Choices.\n     * This can also be used to add groups of choices (see example 2); Optionally pass a true `replaceChoices` value to remove any existing choices.\n     * Optionally pass a `customProperties` object to add additional data to your choices (useful when searching/filtering etc).\n     *\n     * **Input types affected:** select-one, select-multiple\n     *\n     * @example\n     * ```js\n     * const example = new Choices(element);\n     *\n     * example.setChoices([\n     *   {value: 'One', label: 'Label One', disabled: true},\n     *   {value: 'Two', label: 'Label Two', selected: true},\n     *   {value: 'Three', label: 'Label Three'},\n     * ], 'value', 'label', false);\n     * ```\n     *\n     * @example\n     * ```js\n     * const example = new Choices(element);\n     *\n     * example.setChoices(async () => {\n     *   try {\n     *      const items = await fetch('/items');\n     *      return items.json()\n     *   } catch(err) {\n     *      console.error(err)\n     *   }\n     * });\n     * ```\n     *\n     * @example\n     * ```js\n     * const example = new Choices(element);\n     *\n     * example.setChoices([{\n     *   label: 'Group one',\n     *   id: 1,\n     *   disabled: false,\n     *   choices: [\n     *     {value: 'Child One', label: 'Child One', selected: true},\n     *     {value: 'Child Two', label: 'Child Two',  disabled: true},\n     *     {value: 'Child Three', label: 'Child Three'},\n     *   ]\n     * },\n     * {\n     *   label: 'Group two',\n     *   id: 2,\n     *   disabled: false,\n     *   choices: [\n     *     {value: 'Child Four', label: 'Child Four', disabled: true},\n     *     {value: 'Child Five', label: 'Child Five'},\n     *     {value: 'Child Six', label: 'Child Six', customProperties: {\n     *       description: 'Custom description about child six',\n     *       random: 'Another random custom property'\n     *     }},\n     *   ]\n     * }], 'value', 'label', false);\n     * ```\n     */\n    Choices.prototype.setChoices = function (choicesArrayOrFetcher, value, label, replaceChoices, clearSearchFlag, replaceItems) {\n        var _this = this;\n        if (choicesArrayOrFetcher === void 0) { choicesArrayOrFetcher = []; }\n        if (value === void 0) { value = 'value'; }\n        if (label === void 0) { label = 'label'; }\n        if (replaceChoices === void 0) { replaceChoices = false; }\n        if (clearSearchFlag === void 0) { clearSearchFlag = true; }\n        if (replaceItems === void 0) { replaceItems = false; }\n        if (!this.initialisedOK) {\n            this._warnChoicesInitFailed('setChoices');\n            return this;\n        }\n        if (!this._isSelectElement) {\n            throw new TypeError(\"setChoices can't be used with INPUT based Choices\");\n        }\n        if (typeof value !== 'string' || !value) {\n            throw new TypeError(\"value parameter must be a name of 'value' field in passed objects\");\n        }\n        if (typeof choicesArrayOrFetcher === 'function') {\n            // it's a choices fetcher function\n            var fetcher_1 = choicesArrayOrFetcher(this);\n            if (typeof Promise === 'function' && fetcher_1 instanceof Promise) {\n                // that's a promise\n                // eslint-disable-next-line no-promise-executor-return\n                return new Promise(function (resolve) { return requestAnimationFrame(resolve); })\n                    .then(function () { return _this._handleLoadingState(true); })\n                    .then(function () { return fetcher_1; })\n                    .then(function (data) {\n                    return _this.setChoices(data, value, label, replaceChoices, clearSearchFlag, replaceItems);\n                })\n                    .catch(function (err) {\n                    if (!_this.config.silent) {\n                        console.error(err);\n                    }\n                })\n                    .then(function () { return _this._handleLoadingState(false); })\n                    .then(function () { return _this; });\n            }\n            // function returned something else than promise, let's check if it's an array of choices\n            if (!Array.isArray(fetcher_1)) {\n                throw new TypeError(\".setChoices first argument function must return either array of choices or Promise, got: \".concat(typeof fetcher_1));\n            }\n            // recursion with results, it's sync and choices were cleared already\n            return this.setChoices(fetcher_1, value, label, false);\n        }\n        if (!Array.isArray(choicesArrayOrFetcher)) {\n            throw new TypeError(\".setChoices must be called either with array of choices with a function resulting into Promise of array of choices\");\n        }\n        this.containerOuter.removeLoadingState();\n        this._store.withTxn(function () {\n            if (clearSearchFlag) {\n                _this._isSearching = false;\n            }\n            // Clear choices if needed\n            if (replaceChoices) {\n                _this.clearChoices(true, replaceItems);\n            }\n            var isDefaultValue = value === 'value';\n            var isDefaultLabel = label === 'label';\n            choicesArrayOrFetcher.forEach(function (groupOrChoice) {\n                if ('choices' in groupOrChoice) {\n                    var group = groupOrChoice;\n                    if (!isDefaultLabel) {\n                        group = __assign(__assign({}, group), { label: group[label] });\n                    }\n                    _this._addGroup(mapInputToChoice(group, true));\n                }\n                else {\n                    var choice = groupOrChoice;\n                    if (!isDefaultLabel || !isDefaultValue) {\n                        choice = __assign(__assign({}, choice), { value: choice[value], label: choice[label] });\n                    }\n                    var choiceFull = mapInputToChoice(choice, false);\n                    _this._addChoice(choiceFull);\n                    if (choiceFull.placeholder && !_this._hasNonChoicePlaceholder) {\n                        _this._placeholderValue = unwrapStringForEscaped(choiceFull.label);\n                    }\n                }\n            });\n            _this.unhighlightAll();\n        });\n        // @todo integrate with Store\n        this._searcher.reset();\n        return this;\n    };\n    Choices.prototype.refresh = function (withEvents, selectFirstOption, deselectAll) {\n        var _this = this;\n        if (withEvents === void 0) { withEvents = false; }\n        if (selectFirstOption === void 0) { selectFirstOption = false; }\n        if (deselectAll === void 0) { deselectAll = false; }\n        if (!this._isSelectElement) {\n            if (!this.config.silent) {\n                console.warn('refresh method can only be used on choices backed by a <select> element');\n            }\n            return this;\n        }\n        this._store.withTxn(function () {\n            var choicesFromOptions = _this.passedElement.optionsAsChoices();\n            // Build the list of items which require preserving\n            var existingItems = {};\n            if (!deselectAll) {\n                _this._store.items.forEach(function (choice) {\n                    if (choice.id && choice.active && choice.selected) {\n                        existingItems[choice.value] = true;\n                    }\n                });\n            }\n            _this.clearStore(false);\n            var updateChoice = function (choice) {\n                if (deselectAll) {\n                    _this._store.dispatch(removeItem$1(choice));\n                }\n                else if (existingItems[choice.value]) {\n                    choice.selected = true;\n                }\n            };\n            choicesFromOptions.forEach(function (groupOrChoice) {\n                if ('choices' in groupOrChoice) {\n                    groupOrChoice.choices.forEach(updateChoice);\n                    return;\n                }\n                updateChoice(groupOrChoice);\n            });\n            /* @todo only generate add events for the added options instead of all\n            if (withEvents) {\n              items.forEach((choice) => {\n                if (existingItems[choice.value]) {\n                  this.passedElement.triggerEvent(\n                    EventType.removeItem,\n                    this._getChoiceForEvent(choice),\n                  );\n                }\n              });\n            }\n            */\n            // load new choices & items\n            _this._addPredefinedChoices(choicesFromOptions, selectFirstOption, withEvents);\n            // re-do search if required\n            if (_this._isSearching) {\n                _this._searchChoices(_this.input.value);\n            }\n        });\n        return this;\n    };\n    Choices.prototype.removeChoice = function (value) {\n        var choice = this._store.choices.find(function (c) { return c.value === value; });\n        if (!choice) {\n            return this;\n        }\n        this._clearNotice();\n        this._store.dispatch(removeChoice(choice));\n        // @todo integrate with Store\n        this._searcher.reset();\n        if (choice.selected) {\n            this.passedElement.triggerEvent(EventType.removeItem, getChoiceForOutput(choice));\n        }\n        return this;\n    };\n    Choices.prototype.clearChoices = function (clearOptions, clearItems) {\n        var _this = this;\n        if (clearOptions === void 0) { clearOptions = true; }\n        if (clearItems === void 0) { clearItems = false; }\n        if (clearOptions) {\n            if (clearItems) {\n                this.passedElement.element.replaceChildren('');\n            }\n            else {\n                this.passedElement.element.querySelectorAll(':not([selected])').forEach(function (el) {\n                    el.remove();\n                });\n            }\n        }\n        this.itemList.element.replaceChildren('');\n        this.choiceList.element.replaceChildren('');\n        this._clearNotice();\n        this._store.withTxn(function () {\n            var items = clearItems ? [] : _this._store.items;\n            _this._store.reset();\n            items.forEach(function (item) {\n                _this._store.dispatch(addChoice(item));\n                _this._store.dispatch(addItem(item));\n            });\n        });\n        // @todo integrate with Store\n        this._searcher.reset();\n        return this;\n    };\n    Choices.prototype.clearStore = function (clearOptions) {\n        if (clearOptions === void 0) { clearOptions = true; }\n        this.clearChoices(clearOptions, true);\n        this._stopSearch();\n        this._lastAddedChoiceId = 0;\n        this._lastAddedGroupId = 0;\n        return this;\n    };\n    Choices.prototype.clearInput = function () {\n        var shouldSetInputWidth = !this._isSelectOneElement;\n        this.input.clear(shouldSetInputWidth);\n        this._stopSearch();\n        return this;\n    };\n    Choices.prototype._validateConfig = function () {\n        var config = this.config;\n        var invalidConfigOptions = diff(config, DEFAULT_CONFIG);\n        if (invalidConfigOptions.length) {\n            console.warn('Unknown config option(s) passed', invalidConfigOptions.join(', '));\n        }\n        if (config.allowHTML && config.allowHtmlUserInput) {\n            if (config.addItems) {\n                console.warn('Warning: allowHTML/allowHtmlUserInput/addItems all being true is strongly not recommended and may lead to XSS attacks');\n            }\n            if (config.addChoices) {\n                console.warn('Warning: allowHTML/allowHtmlUserInput/addChoices all being true is strongly not recommended and may lead to XSS attacks');\n            }\n        }\n    };\n    Choices.prototype._render = function (changes) {\n        if (changes === void 0) { changes = { choices: true, groups: true, items: true }; }\n        if (this._store.inTxn()) {\n            return;\n        }\n        if (this._isSelectElement) {\n            if (changes.choices || changes.groups) {\n                this._renderChoices();\n            }\n        }\n        if (changes.items) {\n            this._renderItems();\n        }\n    };\n    Choices.prototype._renderChoices = function () {\n        var _this = this;\n        if (!this._canAddItems()) {\n            return; // block rendering choices if the input limit is reached.\n        }\n        var _a = this, config = _a.config, isSearching = _a._isSearching;\n        var _b = this._store, activeGroups = _b.activeGroups, activeChoices = _b.activeChoices;\n        var renderLimit = isSearching ? config.searchResultLimit : config.renderChoiceLimit;\n        if (this._isSelectElement) {\n            var backingOptions = activeChoices.filter(function (choice) { return !choice.element; });\n            if (backingOptions.length) {\n                this.passedElement.addOptions(backingOptions);\n            }\n        }\n        var fragment = document.createDocumentFragment();\n        var renderableChoices = function (choices) {\n            return choices.filter(function (choice) {\n                return !choice.placeholder &&\n                    (isSearching\n                        ? (config.searchRenderSelectedChoices || !choice.selected) && !!choice.rank\n                        : config.renderSelectedChoices || !choice.selected);\n            });\n        };\n        var showLabel = config.appendGroupInSearch && isSearching;\n        var selectableChoices = false;\n        var highlightedEl = null;\n        var renderChoices = function (choices, withinGroup) {\n            if (isSearching) {\n                // sortByRank is used to ensure stable sorting, as scores are non-unique\n                // this additionally ensures fuseOptions.sortFn is not ignored\n                choices.sort(sortByRank);\n            }\n            else if (config.shouldSort) {\n                choices.sort(config.sorter);\n            }\n            var choiceLimit = choices.length;\n            choiceLimit = !withinGroup && renderLimit > 0 && choiceLimit > renderLimit ? renderLimit : choiceLimit;\n            choiceLimit--;\n            choices.every(function (choice, index) {\n                // choiceEl being empty signals the contents has probably significantly changed\n                var dropdownItem = choice.choiceEl ||\n                    _this._templates.choice(config, choice, config.itemSelectText, showLabel && choice.group ? choice.group.label : undefined);\n                choice.choiceEl = dropdownItem;\n                fragment.appendChild(dropdownItem);\n                if (isSearching || !choice.selected) {\n                    selectableChoices = true;\n                }\n                else if (!highlightedEl) {\n                    highlightedEl = dropdownItem;\n                }\n                return index < choiceLimit;\n            });\n        };\n        if (activeChoices.length) {\n            if (config.resetScrollPosition) {\n                requestAnimationFrame(function () { return _this.choiceList.scrollToTop(); });\n            }\n            if (!this._hasNonChoicePlaceholder && !isSearching && this._isSelectOneElement) {\n                // If we have a placeholder choice along with groups\n                renderChoices(activeChoices.filter(function (choice) { return choice.placeholder && !choice.group; }), false);\n            }\n            // If we have grouped options\n            if (activeGroups.length && !isSearching) {\n                if (config.shouldSort) {\n                    activeGroups.sort(config.sorter);\n                }\n                // render Choices without group first, regardless of sort, otherwise they won't be distinguishable\n                // from the last group\n                renderChoices(activeChoices.filter(function (choice) { return !choice.placeholder && !choice.group; }), false);\n                activeGroups.forEach(function (group) {\n                    var groupChoices = renderableChoices(group.choices);\n                    if (groupChoices.length) {\n                        if (group.label) {\n                            var dropdownGroup = group.groupEl || _this._templates.choiceGroup(_this.config, group);\n                            group.groupEl = dropdownGroup;\n                            dropdownGroup.remove();\n                            fragment.appendChild(dropdownGroup);\n                        }\n                        renderChoices(groupChoices, true);\n                    }\n                });\n            }\n            else {\n                renderChoices(renderableChoices(activeChoices), false);\n            }\n        }\n        if (!selectableChoices && (isSearching || !fragment.children.length || !config.renderSelectedChoices)) {\n            if (!this._notice) {\n                this._notice = {\n                    text: resolveStringFunction(isSearching ? config.noResultsText : config.noChoicesText),\n                    type: isSearching ? NoticeTypes.noResults : NoticeTypes.noChoices,\n                };\n            }\n            fragment.replaceChildren('');\n        }\n        this._renderNotice(fragment);\n        this.choiceList.element.replaceChildren(fragment);\n        this._highlightChoice(highlightedEl);\n    };\n    Choices.prototype._renderItems = function () {\n        var _this = this;\n        var items = this._store.items || [];\n        var itemList = this.itemList.element;\n        var config = this.config;\n        var fragment = document.createDocumentFragment();\n        var itemFromList = function (item) {\n            return itemList.querySelector(\"[data-item][data-id=\\\"\".concat(item.id, \"\\\"]\"));\n        };\n        var addItemToFragment = function (item) {\n            var el = item.itemEl;\n            if (el && el.parentElement) {\n                return;\n            }\n            el = itemFromList(item) || _this._templates.item(config, item, config.removeItemButton);\n            item.itemEl = el;\n            fragment.appendChild(el);\n        };\n        // new items\n        items.forEach(addItemToFragment);\n        var addedItems = !!fragment.childNodes.length;\n        if (this._isSelectOneElement) {\n            var existingItems = itemList.children.length;\n            if (addedItems || existingItems > 1) {\n                var placeholder = itemList.querySelector(getClassNamesSelector(config.classNames.placeholder));\n                if (placeholder) {\n                    placeholder.remove();\n                }\n            }\n            else if (!addedItems && !existingItems && this._placeholderValue) {\n                addedItems = true;\n                addItemToFragment(mapInputToChoice({\n                    selected: true,\n                    value: '',\n                    label: this._placeholderValue,\n                    placeholder: true,\n                }, false));\n            }\n        }\n        if (addedItems) {\n            itemList.append(fragment);\n            if (config.shouldSortItems && !this._isSelectOneElement) {\n                items.sort(config.sorter);\n                // push sorting into the DOM\n                items.forEach(function (item) {\n                    var el = itemFromList(item);\n                    if (el) {\n                        el.remove();\n                        fragment.append(el);\n                    }\n                });\n                itemList.append(fragment);\n            }\n        }\n        if (this._isTextElement) {\n            // Update the value of the hidden input\n            this.passedElement.value = items.map(function (_a) {\n                var value = _a.value;\n                return value;\n            }).join(config.delimiter);\n        }\n    };\n    Choices.prototype._displayNotice = function (text, type, openDropdown) {\n        if (openDropdown === void 0) { openDropdown = true; }\n        var oldNotice = this._notice;\n        if (oldNotice &&\n            ((oldNotice.type === type && oldNotice.text === text) ||\n                (oldNotice.type === NoticeTypes.addChoice &&\n                    (type === NoticeTypes.noResults || type === NoticeTypes.noChoices)))) {\n            if (openDropdown) {\n                this.showDropdown(true);\n            }\n            return;\n        }\n        this._clearNotice();\n        this._notice = text\n            ? {\n                text: text,\n                type: type,\n            }\n            : undefined;\n        this._renderNotice();\n        if (openDropdown && text) {\n            this.showDropdown(true);\n        }\n    };\n    Choices.prototype._clearNotice = function () {\n        if (!this._notice) {\n            return;\n        }\n        var noticeElement = this.choiceList.element.querySelector(getClassNamesSelector(this.config.classNames.notice));\n        if (noticeElement) {\n            noticeElement.remove();\n        }\n        this._notice = undefined;\n    };\n    Choices.prototype._renderNotice = function (fragment) {\n        var noticeConf = this._notice;\n        if (noticeConf) {\n            var notice = this._templates.notice(this.config, noticeConf.text, noticeConf.type);\n            if (fragment) {\n                fragment.append(notice);\n            }\n            else {\n                this.choiceList.prepend(notice);\n            }\n        }\n    };\n    /**\n     * @deprecated Use utils.getChoiceForOutput\n     */\n    // eslint-disable-next-line class-methods-use-this\n    Choices.prototype._getChoiceForOutput = function (choice, keyCode) {\n        return getChoiceForOutput(choice, keyCode);\n    };\n    Choices.prototype._triggerChange = function (value) {\n        if (value === undefined || value === null) {\n            return;\n        }\n        this.passedElement.triggerEvent(EventType.change, {\n            value: value,\n        });\n    };\n    Choices.prototype._handleButtonAction = function (element) {\n        var _this = this;\n        var items = this._store.items;\n        if (!items.length || !this.config.removeItems || !this.config.removeItemButton) {\n            return;\n        }\n        var id = element && parseDataSetId(element.closest('[data-id]'));\n        var itemToRemove = id && items.find(function (item) { return item.id === id; });\n        if (!itemToRemove) {\n            return;\n        }\n        this._store.withTxn(function () {\n            // Remove item associated with button\n            _this._removeItem(itemToRemove);\n            _this._triggerChange(itemToRemove.value);\n            if (_this._isSelectOneElement && !_this._hasNonChoicePlaceholder) {\n                var placeholderChoice = (_this.config.shouldSort ? _this._store.choices.reverse() : _this._store.choices).find(function (choice) { return choice.placeholder; });\n                if (placeholderChoice) {\n                    _this._addItem(placeholderChoice);\n                    _this.unhighlightAll();\n                    if (placeholderChoice.value) {\n                        _this._triggerChange(placeholderChoice.value);\n                    }\n                }\n            }\n        });\n    };\n    Choices.prototype._handleItemAction = function (element, hasShiftKey) {\n        var _this = this;\n        if (hasShiftKey === void 0) { hasShiftKey = false; }\n        var items = this._store.items;\n        if (!items.length || !this.config.removeItems || this._isSelectOneElement) {\n            return;\n        }\n        var id = parseDataSetId(element);\n        if (!id) {\n            return;\n        }\n        // We only want to select one item with a click\n        // so we deselect any items that aren't the target\n        // unless shift is being pressed\n        items.forEach(function (item) {\n            if (item.id === id && !item.highlighted) {\n                _this.highlightItem(item);\n            }\n            else if (!hasShiftKey && item.highlighted) {\n                _this.unhighlightItem(item);\n            }\n        });\n        // Focus input as without focus, a user cannot do anything with a\n        // highlighted item\n        this.input.focus();\n    };\n    Choices.prototype._handleChoiceAction = function (element) {\n        var _this = this;\n        // If we are clicking on an option\n        var id = parseDataSetId(element);\n        var choice = id && this._store.getChoiceById(id);\n        if (!choice || choice.disabled) {\n            return false;\n        }\n        var hasActiveDropdown = this.dropdown.isActive;\n        if (!choice.selected) {\n            if (!this._canAddItems()) {\n                return true; // causes _onEnterKey to early out\n            }\n            this._store.withTxn(function () {\n                _this._addItem(choice, true, true);\n                _this.clearInput();\n                _this.unhighlightAll();\n            });\n            this._triggerChange(choice.value);\n        }\n        // We want to close the dropdown if we are dealing with a single select box\n        if (hasActiveDropdown && this.config.closeDropdownOnSelect) {\n            this.hideDropdown(true);\n            this.containerOuter.element.focus();\n        }\n        return true;\n    };\n    Choices.prototype._handleBackspace = function (items) {\n        var config = this.config;\n        if (!config.removeItems || !items.length) {\n            return;\n        }\n        var lastItem = items[items.length - 1];\n        var hasHighlightedItems = items.some(function (item) { return item.highlighted; });\n        // If editing the last item is allowed and there are not other selected items,\n        // we can edit the item value. Otherwise if we can remove items, remove all selected items\n        if (config.editItems && !hasHighlightedItems && lastItem) {\n            this.input.value = lastItem.value;\n            this.input.setWidth();\n            this._removeItem(lastItem);\n            this._triggerChange(lastItem.value);\n        }\n        else {\n            if (!hasHighlightedItems) {\n                // Highlight last item if none already highlighted\n                this.highlightItem(lastItem, false);\n            }\n            this.removeHighlightedItems(true);\n        }\n    };\n    Choices.prototype._loadChoices = function () {\n        var _a;\n        var _this = this;\n        var config = this.config;\n        if (this._isTextElement) {\n            // Assign preset items from passed object first\n            this._presetChoices = config.items.map(function (e) { return mapInputToChoice(e, false); });\n            // Add any values passed from attribute\n            if (this.passedElement.value) {\n                var elementItems = this.passedElement.value\n                    .split(config.delimiter)\n                    .map(function (e) { return mapInputToChoice(e, false, _this.config.allowHtmlUserInput); });\n                this._presetChoices = this._presetChoices.concat(elementItems);\n            }\n            this._presetChoices.forEach(function (choice) {\n                choice.selected = true;\n            });\n        }\n        else if (this._isSelectElement) {\n            // Assign preset choices from passed object\n            this._presetChoices = config.choices.map(function (e) { return mapInputToChoice(e, true); });\n            // Create array of choices from option elements\n            var choicesFromOptions = this.passedElement.optionsAsChoices();\n            if (choicesFromOptions) {\n                (_a = this._presetChoices).push.apply(_a, choicesFromOptions);\n            }\n        }\n    };\n    Choices.prototype._handleLoadingState = function (setLoading) {\n        if (setLoading === void 0) { setLoading = true; }\n        var el = this.itemList.element;\n        if (setLoading) {\n            this.disable();\n            this.containerOuter.addLoadingState();\n            if (this._isSelectOneElement) {\n                el.replaceChildren(this._templates.placeholder(this.config, this.config.loadingText));\n            }\n            else {\n                this.input.placeholder = this.config.loadingText;\n            }\n        }\n        else {\n            this.enable();\n            this.containerOuter.removeLoadingState();\n            if (this._isSelectOneElement) {\n                el.replaceChildren('');\n                this._render();\n            }\n            else {\n                this.input.placeholder = this._placeholderValue || '';\n            }\n        }\n    };\n    Choices.prototype._handleSearch = function (value) {\n        if (!this.input.isFocussed) {\n            return;\n        }\n        // Check that we have a value to search and the input was an alphanumeric character\n        if (value !== null && typeof value !== 'undefined' && value.length >= this.config.searchFloor) {\n            var resultCount = this.config.searchChoices ? this._searchChoices(value) : 0;\n            if (resultCount !== null) {\n                // Trigger search event\n                this.passedElement.triggerEvent(EventType.search, {\n                    value: value,\n                    resultCount: resultCount,\n                });\n            }\n        }\n        else if (this._store.choices.some(function (option) { return !option.active; })) {\n            this._stopSearch();\n        }\n    };\n    Choices.prototype._canAddItems = function () {\n        var config = this.config;\n        var maxItemCount = config.maxItemCount, maxItemText = config.maxItemText;\n        if (!config.singleModeForMultiSelect && maxItemCount > 0 && maxItemCount <= this._store.items.length) {\n            this.choiceList.element.replaceChildren('');\n            this._notice = undefined;\n            this._displayNotice(typeof maxItemText === 'function' ? maxItemText(maxItemCount) : maxItemText, NoticeTypes.addChoice);\n            return false;\n        }\n        if (this._notice && this._notice.type === NoticeTypes.addChoice) {\n            this._clearNotice();\n        }\n        return true;\n    };\n    Choices.prototype._canCreateItem = function (value) {\n        var config = this.config;\n        var canAddItem = true;\n        var notice = '';\n        if (canAddItem && typeof config.addItemFilter === 'function' && !config.addItemFilter(value)) {\n            canAddItem = false;\n            notice = resolveNoticeFunction(config.customAddItemText, value, undefined);\n        }\n        if (canAddItem) {\n            var foundChoice = this._store.choices.find(function (choice) { return config.valueComparer(choice.value, value); });\n            if (foundChoice) {\n                if (this._isSelectElement) {\n                    // for exact matches, do not prompt to add it as a custom choice\n                    this._displayNotice('', NoticeTypes.addChoice);\n                    return false;\n                }\n                if (!config.duplicateItemsAllowed) {\n                    canAddItem = false;\n                    notice = resolveNoticeFunction(config.uniqueItemText, value, undefined);\n                }\n            }\n        }\n        if (canAddItem) {\n            notice = resolveNoticeFunction(config.addItemText, value, undefined);\n        }\n        if (notice) {\n            this._displayNotice(notice, NoticeTypes.addChoice);\n        }\n        return canAddItem;\n    };\n    Choices.prototype._searchChoices = function (value) {\n        var newValue = value.trim().replace(/\\s{2,}/, ' ');\n        // signal input didn't change search\n        if (!newValue.length || newValue === this._currentValue) {\n            return null;\n        }\n        var searcher = this._searcher;\n        if (searcher.isEmptyIndex()) {\n            searcher.index(this._store.searchableChoices);\n        }\n        // If new value matches the desired length and is not the same as the current value with a space\n        var results = searcher.search(newValue);\n        this._currentValue = newValue;\n        this._highlightPosition = 0;\n        this._isSearching = true;\n        var notice = this._notice;\n        var noticeType = notice && notice.type;\n        if (noticeType !== NoticeTypes.addChoice) {\n            if (!results.length) {\n                this._displayNotice(resolveStringFunction(this.config.noResultsText), NoticeTypes.noResults);\n            }\n            else {\n                this._clearNotice();\n            }\n        }\n        this._store.dispatch(filterChoices(results));\n        return results.length;\n    };\n    Choices.prototype._stopSearch = function () {\n        if (this._isSearching) {\n            this._currentValue = '';\n            this._isSearching = false;\n            this._clearNotice();\n            this._store.dispatch(activateChoices(true));\n            this.passedElement.triggerEvent(EventType.search, {\n                value: '',\n                resultCount: 0,\n            });\n        }\n    };\n    Choices.prototype._addEventListeners = function () {\n        var documentElement = this._docRoot;\n        var outerElement = this.containerOuter.element;\n        var inputElement = this.input.element;\n        var passedElement = this.passedElement.element;\n        // capture events - can cancel event processing or propagation\n        documentElement.addEventListener('touchend', this._onTouchEnd, true);\n        outerElement.addEventListener('keydown', this._onKeyDown, true);\n        outerElement.addEventListener('mousedown', this._onMouseDown, true);\n        // passive events - doesn't call `preventDefault` or `stopPropagation`\n        documentElement.addEventListener('click', this._onClick, { passive: true });\n        documentElement.addEventListener('touchmove', this._onTouchMove, {\n            passive: true,\n        });\n        this.dropdown.element.addEventListener('mouseover', this._onMouseOver, {\n            passive: true,\n        });\n        if (this._isSelectOneElement) {\n            outerElement.addEventListener('focus', this._onFocus, {\n                passive: true,\n            });\n            outerElement.addEventListener('blur', this._onBlur, {\n                passive: true,\n            });\n        }\n        inputElement.addEventListener('keyup', this._onKeyUp, {\n            passive: true,\n        });\n        inputElement.addEventListener('input', this._onInput, {\n            passive: true,\n        });\n        inputElement.addEventListener('focus', this._onFocus, {\n            passive: true,\n        });\n        inputElement.addEventListener('blur', this._onBlur, {\n            passive: true,\n        });\n        if (inputElement.form) {\n            inputElement.form.addEventListener('reset', this._onFormReset, {\n                passive: true,\n            });\n        }\n        if (passedElement.hasAttribute('required')) {\n            passedElement.addEventListener('change', this._onChange, {\n                passive: true,\n            });\n            passedElement.addEventListener('invalid', this._onInvalid, {\n                passive: true,\n            });\n        }\n        this.input.addEventListeners();\n    };\n    Choices.prototype._removeEventListeners = function () {\n        var documentElement = this._docRoot;\n        var outerElement = this.containerOuter.element;\n        var inputElement = this.input.element;\n        var passedElement = this.passedElement.element;\n        documentElement.removeEventListener('touchend', this._onTouchEnd, true);\n        outerElement.removeEventListener('keydown', this._onKeyDown, true);\n        outerElement.removeEventListener('mousedown', this._onMouseDown, true);\n        documentElement.removeEventListener('click', this._onClick);\n        documentElement.removeEventListener('touchmove', this._onTouchMove);\n        this.dropdown.element.removeEventListener('mouseover', this._onMouseOver);\n        if (this._isSelectOneElement) {\n            outerElement.removeEventListener('focus', this._onFocus);\n            outerElement.removeEventListener('blur', this._onBlur);\n        }\n        inputElement.removeEventListener('keyup', this._onKeyUp);\n        inputElement.removeEventListener('input', this._onInput);\n        inputElement.removeEventListener('focus', this._onFocus);\n        inputElement.removeEventListener('blur', this._onBlur);\n        if (inputElement.form) {\n            inputElement.form.removeEventListener('reset', this._onFormReset);\n        }\n        if (passedElement.hasAttribute('required')) {\n            passedElement.removeEventListener('change', this._onChange);\n            passedElement.removeEventListener('invalid', this._onInvalid);\n        }\n        this.input.removeEventListeners();\n    };\n    Choices.prototype._onKeyDown = function (event) {\n        var keyCode = event.keyCode;\n        var hasActiveDropdown = this.dropdown.isActive;\n        /*\n        See:\n        https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key\n        https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values\n        https://en.wikipedia.org/wiki/UTF-16#Code_points_from_U+010000_to_U+10FFFF - UTF-16 surrogate pairs\n        https://stackoverflow.com/a/70866532 - \"Unidentified\" for mobile\n        http://www.unicode.org/versions/Unicode5.2.0/ch16.pdf#G19635 - U+FFFF is reserved (Section 16.7)\n    \n        Logic: when a key event is sent, `event.key` represents its printable value _or_ one\n        of a large list of special values indicating meta keys/functionality. In addition,\n        key events for compose functionality contain a value of `Dead` when mid-composition.\n    \n        I can't quite verify it, but non-English IMEs may also be able to generate key codes\n        for code points in the surrogate-pair range, which could potentially be seen as having\n        key.length > 1. Since `Fn` is one of the special keys, we can't distinguish by that\n        alone.\n    \n        Here, key.length === 1 means we know for sure the input was printable and not a special\n        `key` value. When the length is greater than 1, it could be either a printable surrogate\n        pair or a special `key` value. We can tell the difference by checking if the _character\n        code_ value (not code point!) is in the \"surrogate pair\" range or not.\n    \n        We don't use .codePointAt because an invalid code point would return 65535, which wouldn't\n        pass the >= 0x10000 check we would otherwise use.\n    \n        > ...The Unicode Standard sets aside 66 noncharacter code points. The last two code points\n        > of each plane are noncharacters: U+FFFE and U+FFFF on the BMP...\n        */\n        var wasPrintableChar = event.key.length === 1 ||\n            (event.key.length === 2 && event.key.charCodeAt(0) >= 0xd800) ||\n            event.key === 'Unidentified';\n        /*\n          We do not show the dropdown if focusing out with esc or navigating through input fields.\n          An activated search can still be opened with any other key.\n         */\n        if (!this._isTextElement &&\n            !hasActiveDropdown &&\n            keyCode !== KeyCodeMap.ESC_KEY &&\n            keyCode !== KeyCodeMap.TAB_KEY &&\n            keyCode !== KeyCodeMap.SHIFT_KEY) {\n            this.showDropdown();\n            if (!this.input.isFocussed && wasPrintableChar) {\n                /*\n                  We update the input value with the pressed key as\n                  the input was not focussed at the time of key press\n                  therefore does not have the value of the key.\n                */\n                this.input.value += event.key;\n                // browsers interpret a space as pagedown\n                if (event.key === ' ') {\n                    event.preventDefault();\n                }\n            }\n        }\n        switch (keyCode) {\n            case KeyCodeMap.A_KEY:\n                return this._onSelectKey(event, this.itemList.element.hasChildNodes());\n            case KeyCodeMap.ENTER_KEY:\n                return this._onEnterKey(event, hasActiveDropdown);\n            case KeyCodeMap.ESC_KEY:\n                return this._onEscapeKey(event, hasActiveDropdown);\n            case KeyCodeMap.UP_KEY:\n            case KeyCodeMap.PAGE_UP_KEY:\n            case KeyCodeMap.DOWN_KEY:\n            case KeyCodeMap.PAGE_DOWN_KEY:\n                return this._onDirectionKey(event, hasActiveDropdown);\n            case KeyCodeMap.DELETE_KEY:\n            case KeyCodeMap.BACK_KEY:\n                return this._onDeleteKey(event, this._store.items, this.input.isFocussed);\n        }\n    };\n    Choices.prototype._onKeyUp = function ( /* event: KeyboardEvent */) {\n        this._canSearch = this.config.searchEnabled;\n    };\n    Choices.prototype._onInput = function ( /* event: InputEvent */) {\n        var value = this.input.value;\n        if (!value) {\n            if (this._isTextElement) {\n                this.hideDropdown(true);\n            }\n            else {\n                this._stopSearch();\n            }\n            return;\n        }\n        if (!this._canAddItems()) {\n            return;\n        }\n        if (this._canSearch) {\n            // do the search even if the entered text can not be added\n            this._handleSearch(value);\n        }\n        if (!this._canAddUserChoices) {\n            return;\n        }\n        // determine if a notice needs to be displayed for why a search result can't be added\n        this._canCreateItem(value);\n        if (this._isSelectElement) {\n            this._highlightPosition = 0; // reset to select the notice and/or exact match\n            this._highlightChoice();\n        }\n    };\n    Choices.prototype._onSelectKey = function (event, hasItems) {\n        // If CTRL + A or CMD + A have been pressed and there are items to select\n        if ((event.ctrlKey || event.metaKey) && hasItems) {\n            this._canSearch = false;\n            var shouldHightlightAll = this.config.removeItems && !this.input.value && this.input.element === document.activeElement;\n            if (shouldHightlightAll) {\n                this.highlightAll();\n            }\n        }\n    };\n    Choices.prototype._onEnterKey = function (event, hasActiveDropdown) {\n        var _this = this;\n        var value = this.input.value;\n        var target = event.target;\n        event.preventDefault();\n        if (target && target.hasAttribute('data-button')) {\n            this._handleButtonAction(target);\n            return;\n        }\n        if (!hasActiveDropdown) {\n            if (this._isSelectElement || this._notice) {\n                this.showDropdown();\n            }\n            return;\n        }\n        var highlightedChoice = this.dropdown.element.querySelector(getClassNamesSelector(this.config.classNames.highlightedState));\n        if (highlightedChoice && this._handleChoiceAction(highlightedChoice)) {\n            return;\n        }\n        if (!target || !value) {\n            this.hideDropdown(true);\n            return;\n        }\n        if (!this._canAddItems()) {\n            return;\n        }\n        var addedItem = false;\n        this._store.withTxn(function () {\n            addedItem = _this._findAndSelectChoiceByValue(value, true);\n            if (!addedItem) {\n                if (!_this._canAddUserChoices) {\n                    return;\n                }\n                if (!_this._canCreateItem(value)) {\n                    return;\n                }\n                _this._addChoice(mapInputToChoice(value, false, _this.config.allowHtmlUserInput), true, true);\n                addedItem = true;\n            }\n            _this.clearInput();\n            _this.unhighlightAll();\n        });\n        if (!addedItem) {\n            return;\n        }\n        this._triggerChange(value);\n        if (this.config.closeDropdownOnSelect) {\n            this.hideDropdown(true);\n        }\n    };\n    Choices.prototype._onEscapeKey = function (event, hasActiveDropdown) {\n        if (hasActiveDropdown) {\n            event.stopPropagation();\n            this.hideDropdown(true);\n            this._stopSearch();\n            this.containerOuter.element.focus();\n        }\n    };\n    Choices.prototype._onDirectionKey = function (event, hasActiveDropdown) {\n        var keyCode = event.keyCode;\n        // If up or down key is pressed, traverse through options\n        if (hasActiveDropdown || this._isSelectOneElement) {\n            this.showDropdown();\n            this._canSearch = false;\n            var directionInt = keyCode === KeyCodeMap.DOWN_KEY || keyCode === KeyCodeMap.PAGE_DOWN_KEY ? 1 : -1;\n            var skipKey = event.metaKey || keyCode === KeyCodeMap.PAGE_DOWN_KEY || keyCode === KeyCodeMap.PAGE_UP_KEY;\n            var nextEl = void 0;\n            if (skipKey) {\n                if (directionInt > 0) {\n                    nextEl = this.dropdown.element.querySelector(\"\".concat(selectableChoiceIdentifier, \":last-of-type\"));\n                }\n                else {\n                    nextEl = this.dropdown.element.querySelector(selectableChoiceIdentifier);\n                }\n            }\n            else {\n                var currentEl = this.dropdown.element.querySelector(getClassNamesSelector(this.config.classNames.highlightedState));\n                if (currentEl) {\n                    nextEl = getAdjacentEl(currentEl, selectableChoiceIdentifier, directionInt);\n                }\n                else {\n                    nextEl = this.dropdown.element.querySelector(selectableChoiceIdentifier);\n                }\n            }\n            if (nextEl) {\n                // We prevent default to stop the cursor moving\n                // when pressing the arrow\n                if (!isScrolledIntoView(nextEl, this.choiceList.element, directionInt)) {\n                    this.choiceList.scrollToChildElement(nextEl, directionInt);\n                }\n                this._highlightChoice(nextEl);\n            }\n            // Prevent default to maintain cursor position whilst\n            // traversing dropdown options\n            event.preventDefault();\n        }\n    };\n    Choices.prototype._onDeleteKey = function (event, items, hasFocusedInput) {\n        // If backspace or delete key is pressed and the input has no value\n        if (!this._isSelectOneElement && !event.target.value && hasFocusedInput) {\n            this._handleBackspace(items);\n            event.preventDefault();\n        }\n    };\n    Choices.prototype._onTouchMove = function () {\n        if (this._wasTap) {\n            this._wasTap = false;\n        }\n    };\n    Choices.prototype._onTouchEnd = function (event) {\n        var target = (event || event.touches[0]).target;\n        var touchWasWithinContainer = this._wasTap && this.containerOuter.element.contains(target);\n        if (touchWasWithinContainer) {\n            var containerWasExactTarget = target === this.containerOuter.element || target === this.containerInner.element;\n            if (containerWasExactTarget) {\n                if (this._isTextElement) {\n                    this.input.focus();\n                }\n                else if (this._isSelectMultipleElement) {\n                    this.showDropdown();\n                }\n            }\n            // Prevents focus event firing\n            event.stopPropagation();\n        }\n        this._wasTap = true;\n    };\n    /**\n     * Handles mousedown event in capture mode for containetOuter.element\n     */\n    Choices.prototype._onMouseDown = function (event) {\n        var target = event.target;\n        if (!(target instanceof Element)) {\n            return;\n        }\n        // If we have our mouse down on the scrollbar and are on IE11...\n        if (IS_IE11 && this.choiceList.element.contains(target)) {\n            // check if click was on a scrollbar area\n            var firstChoice = this.choiceList.element.firstElementChild;\n            this._isScrollingOnIe =\n                this._direction === 'ltr' ? event.offsetX >= firstChoice.offsetWidth : event.offsetX < firstChoice.offsetLeft;\n        }\n        if (target === this.input.element) {\n            return;\n        }\n        var item = target.closest('[data-button],[data-item],[data-choice]');\n        if (item instanceof HTMLElement) {\n            if ('button' in item.dataset) {\n                this._handleButtonAction(item);\n            }\n            else if ('item' in item.dataset) {\n                this._handleItemAction(item, event.shiftKey);\n            }\n            else if ('choice' in item.dataset) {\n                this._handleChoiceAction(item);\n            }\n        }\n        event.preventDefault();\n    };\n    /**\n     * Handles mouseover event over this.dropdown\n     * @param {MouseEvent} event\n     */\n    Choices.prototype._onMouseOver = function (_a) {\n        var target = _a.target;\n        if (target instanceof HTMLElement && 'choice' in target.dataset) {\n            this._highlightChoice(target);\n        }\n    };\n    Choices.prototype._onClick = function (_a) {\n        var target = _a.target;\n        var containerOuter = this.containerOuter;\n        var clickWasWithinContainer = containerOuter.element.contains(target);\n        if (clickWasWithinContainer) {\n            if (!this.dropdown.isActive && !containerOuter.isDisabled) {\n                if (this._isTextElement) {\n                    if (document.activeElement !== this.input.element) {\n                        this.input.focus();\n                    }\n                }\n                else {\n                    this.showDropdown();\n                    containerOuter.element.focus();\n                }\n            }\n            else if (this._isSelectOneElement &&\n                target !== this.input.element &&\n                !this.dropdown.element.contains(target)) {\n                this.hideDropdown();\n            }\n        }\n        else {\n            containerOuter.removeFocusState();\n            this.hideDropdown(true);\n            this.unhighlightAll();\n        }\n    };\n    Choices.prototype._onFocus = function (_a) {\n        var target = _a.target;\n        var containerOuter = this.containerOuter;\n        var focusWasWithinContainer = target && containerOuter.element.contains(target);\n        if (!focusWasWithinContainer) {\n            return;\n        }\n        var targetIsInput = target === this.input.element;\n        if (this._isTextElement) {\n            if (targetIsInput) {\n                containerOuter.addFocusState();\n            }\n        }\n        else if (this._isSelectMultipleElement) {\n            if (targetIsInput) {\n                this.showDropdown(true);\n                // If element is a select box, the focused element is the container and the dropdown\n                // isn't already open, focus and show dropdown\n                containerOuter.addFocusState();\n            }\n        }\n        else {\n            containerOuter.addFocusState();\n            if (targetIsInput) {\n                this.showDropdown(true);\n            }\n        }\n    };\n    Choices.prototype._onBlur = function (_a) {\n        var target = _a.target;\n        var containerOuter = this.containerOuter;\n        var blurWasWithinContainer = target && containerOuter.element.contains(target);\n        if (blurWasWithinContainer && !this._isScrollingOnIe) {\n            if (target === this.input.element) {\n                containerOuter.removeFocusState();\n                this.hideDropdown(true);\n                if (this._isTextElement || this._isSelectMultipleElement) {\n                    this.unhighlightAll();\n                }\n            }\n            else if (target === this.containerOuter.element) {\n                // Remove the focus state when the past outerContainer was the target\n                containerOuter.removeFocusState();\n                // Also close the dropdown if search is disabled\n                if (!this.config.searchEnabled) {\n                    this.hideDropdown(true);\n                }\n            }\n        }\n        else {\n            // On IE11, clicking the scollbar blurs our input and thus\n            // closes the dropdown. To stop this, we refocus our input\n            // if we know we are on IE *and* are scrolling.\n            this._isScrollingOnIe = false;\n            this.input.element.focus();\n        }\n    };\n    Choices.prototype._onFormReset = function () {\n        var _this = this;\n        this._store.withTxn(function () {\n            _this.clearInput();\n            _this.hideDropdown();\n            _this.refresh(false, false, true);\n            if (_this._initialItems.length) {\n                _this.setChoiceByValue(_this._initialItems);\n            }\n        });\n    };\n    Choices.prototype._onChange = function (event) {\n        if (!event.target.checkValidity()) {\n            return;\n        }\n        this.containerOuter.removeInvalidState();\n    };\n    Choices.prototype._onInvalid = function () {\n        this.containerOuter.addInvalidState();\n    };\n    /**\n     * Removes any highlighted choice options\n     */\n    Choices.prototype._removeHighlightedChoices = function () {\n        var highlightedState = this.config.classNames.highlightedState;\n        var highlightedChoices = Array.from(this.dropdown.element.querySelectorAll(getClassNamesSelector(highlightedState)));\n        // Remove any highlighted choices\n        highlightedChoices.forEach(function (choice) {\n            removeClassesFromElement(choice, highlightedState);\n            choice.setAttribute('aria-selected', 'false');\n        });\n    };\n    Choices.prototype._highlightChoice = function (el) {\n        if (el === void 0) { el = null; }\n        var choices = Array.from(this.dropdown.element.querySelectorAll(selectableChoiceIdentifier));\n        if (!choices.length) {\n            return;\n        }\n        var passedEl = el;\n        var highlightedState = this.config.classNames.highlightedState;\n        this._removeHighlightedChoices();\n        if (passedEl) {\n            this._highlightPosition = choices.indexOf(passedEl);\n        }\n        else {\n            // Highlight choice based on last known highlight location\n            if (choices.length > this._highlightPosition) {\n                // If we have an option to highlight\n                passedEl = choices[this._highlightPosition];\n            }\n            else {\n                // Otherwise highlight the option before\n                passedEl = choices[choices.length - 1];\n            }\n            if (!passedEl) {\n                passedEl = choices[0];\n            }\n        }\n        addClassesToElement(passedEl, highlightedState);\n        passedEl.setAttribute('aria-selected', 'true');\n        this.passedElement.triggerEvent(EventType.highlightChoice, {\n            el: passedEl,\n        });\n        if (this.dropdown.isActive) {\n            // IE11 ignores aria-label and blocks virtual keyboard\n            // if aria-activedescendant is set without a dropdown\n            this.input.setActiveDescendant(passedEl.id);\n            this.containerOuter.setActiveDescendant(passedEl.id);\n        }\n    };\n    Choices.prototype._addItem = function (item, withEvents, userTriggered) {\n        if (withEvents === void 0) { withEvents = true; }\n        if (userTriggered === void 0) { userTriggered = false; }\n        if (!item.id) {\n            throw new TypeError('item.id must be set before _addItem is called for a choice/item');\n        }\n        if (this.config.singleModeForMultiSelect || this._isSelectOneElement) {\n            this.removeActiveItems(item.id);\n        }\n        this._store.dispatch(addItem(item));\n        if (withEvents) {\n            var eventChoice = getChoiceForOutput(item);\n            this.passedElement.triggerEvent(EventType.addItem, eventChoice);\n            if (userTriggered) {\n                this.passedElement.triggerEvent(EventType.choice, eventChoice);\n            }\n        }\n    };\n    Choices.prototype._removeItem = function (item) {\n        if (!item.id) {\n            return;\n        }\n        this._store.dispatch(removeItem$1(item));\n        var notice = this._notice;\n        if (notice && notice.type === NoticeTypes.noChoices) {\n            this._clearNotice();\n        }\n        this.passedElement.triggerEvent(EventType.removeItem, getChoiceForOutput(item));\n    };\n    Choices.prototype._addChoice = function (choice, withEvents, userTriggered) {\n        if (withEvents === void 0) { withEvents = true; }\n        if (userTriggered === void 0) { userTriggered = false; }\n        if (choice.id) {\n            throw new TypeError('Can not re-add a choice which has already been added');\n        }\n        var config = this.config;\n        if (!config.duplicateItemsAllowed && this._store.choices.find(function (c) { return config.valueComparer(c.value, choice.value); })) {\n            return;\n        }\n        // Generate unique id, in-place update is required so chaining _addItem works as expected\n        this._lastAddedChoiceId++;\n        choice.id = this._lastAddedChoiceId;\n        choice.elementId = \"\".concat(this._baseId, \"-\").concat(this._idNames.itemChoice, \"-\").concat(choice.id);\n        var prependValue = config.prependValue, appendValue = config.appendValue;\n        if (prependValue) {\n            choice.value = prependValue + choice.value;\n        }\n        if (appendValue) {\n            choice.value += appendValue.toString();\n        }\n        if ((prependValue || appendValue) && choice.element) {\n            choice.element.value = choice.value;\n        }\n        this._clearNotice();\n        this._store.dispatch(addChoice(choice));\n        if (choice.selected) {\n            this._addItem(choice, withEvents, userTriggered);\n        }\n    };\n    Choices.prototype._addGroup = function (group, withEvents) {\n        var _this = this;\n        if (withEvents === void 0) { withEvents = true; }\n        if (group.id) {\n            throw new TypeError('Can not re-add a group which has already been added');\n        }\n        this._store.dispatch(addGroup(group));\n        if (!group.choices) {\n            return;\n        }\n        // add unique id for the group(s), and do not store the full list of choices in this group\n        this._lastAddedGroupId++;\n        group.id = this._lastAddedGroupId;\n        group.choices.forEach(function (item) {\n            item.group = group;\n            if (group.disabled) {\n                item.disabled = true;\n            }\n            _this._addChoice(item, withEvents);\n        });\n    };\n    Choices.prototype._createTemplates = function () {\n        var _this = this;\n        var callbackOnCreateTemplates = this.config.callbackOnCreateTemplates;\n        var userTemplates = {};\n        if (typeof callbackOnCreateTemplates === 'function') {\n            userTemplates = callbackOnCreateTemplates.call(this, strToEl, escapeForTemplate, getClassNames);\n        }\n        var templating = {};\n        Object.keys(this._templates).forEach(function (name) {\n            if (name in userTemplates) {\n                templating[name] = userTemplates[name].bind(_this);\n            }\n            else {\n                templating[name] = _this._templates[name].bind(_this);\n            }\n        });\n        this._templates = templating;\n    };\n    Choices.prototype._createElements = function () {\n        var templating = this._templates;\n        var _a = this, config = _a.config, isSelectOneElement = _a._isSelectOneElement;\n        var position = config.position, classNames = config.classNames;\n        var elementType = this._elementType;\n        this.containerOuter = new Container({\n            element: templating.containerOuter(config, this._direction, this._isSelectElement, isSelectOneElement, config.searchEnabled, elementType, config.labelId),\n            classNames: classNames,\n            type: elementType,\n            position: position,\n        });\n        this.containerInner = new Container({\n            element: templating.containerInner(config),\n            classNames: classNames,\n            type: elementType,\n            position: position,\n        });\n        this.input = new Input({\n            element: templating.input(config, this._placeholderValue),\n            classNames: classNames,\n            type: elementType,\n            preventPaste: !config.paste,\n        });\n        this.choiceList = new List({\n            element: templating.choiceList(config, isSelectOneElement),\n        });\n        this.itemList = new List({\n            element: templating.itemList(config, isSelectOneElement),\n        });\n        this.dropdown = new Dropdown({\n            element: templating.dropdown(config),\n            classNames: classNames,\n            type: elementType,\n        });\n    };\n    Choices.prototype._createStructure = function () {\n        var _a = this, containerInner = _a.containerInner, containerOuter = _a.containerOuter, passedElement = _a.passedElement;\n        var dropdownElement = this.dropdown.element;\n        // Hide original element\n        passedElement.conceal();\n        // Wrap input in container preserving DOM ordering\n        containerInner.wrap(passedElement.element);\n        // Wrapper inner container with outer container\n        containerOuter.wrap(containerInner.element);\n        containerOuter.element.appendChild(containerInner.element);\n        containerOuter.element.appendChild(dropdownElement);\n        containerInner.element.appendChild(this.itemList.element);\n        dropdownElement.appendChild(this.choiceList.element);\n        if (this._isSelectOneElement) {\n            this.input.placeholder = this.config.searchPlaceholderValue || '';\n            if (this.config.searchEnabled) {\n                dropdownElement.insertBefore(this.input.element, dropdownElement.firstChild);\n            }\n        }\n        else {\n            if (!this._isSelectMultipleElement || this.config.searchEnabled) {\n                containerInner.element.appendChild(this.input.element);\n            }\n            if (this._placeholderValue) {\n                this.input.placeholder = this._placeholderValue;\n            }\n            this.input.setWidth();\n        }\n        this._highlightPosition = 0;\n        this._isSearching = false;\n    };\n    Choices.prototype._initStore = function () {\n        var _this = this;\n        this._store.subscribe(this._render).withTxn(function () {\n            _this._addPredefinedChoices(_this._presetChoices, _this._isSelectOneElement && !_this._hasNonChoicePlaceholder, false);\n        });\n        if (!this._store.choices.length || (this._isSelectOneElement && this._hasNonChoicePlaceholder)) {\n            this._render();\n        }\n    };\n    Choices.prototype._addPredefinedChoices = function (choices, selectFirstOption, withEvents) {\n        var _this = this;\n        if (selectFirstOption === void 0) { selectFirstOption = false; }\n        if (withEvents === void 0) { withEvents = true; }\n        if (selectFirstOption) {\n            /**\n             * If there is a selected choice already or the choice is not the first in\n             * the array, add each choice normally.\n             *\n             * Otherwise we pre-select the first enabled choice in the array (\"select-one\" only)\n             */\n            var noSelectedChoices = choices.findIndex(function (choice) { return choice.selected; }) === -1;\n            if (noSelectedChoices) {\n                choices.some(function (choice) {\n                    if (choice.disabled || 'choices' in choice) {\n                        return false;\n                    }\n                    choice.selected = true;\n                    return true;\n                });\n            }\n        }\n        choices.forEach(function (item) {\n            if ('choices' in item) {\n                if (_this._isSelectElement) {\n                    _this._addGroup(item, withEvents);\n                }\n            }\n            else {\n                _this._addChoice(item, withEvents);\n            }\n        });\n    };\n    Choices.prototype._findAndSelectChoiceByValue = function (value, userTriggered) {\n        var _this = this;\n        if (userTriggered === void 0) { userTriggered = false; }\n        // Check 'value' property exists and the choice isn't already selected\n        var foundChoice = this._store.choices.find(function (choice) { return _this.config.valueComparer(choice.value, value); });\n        if (foundChoice && !foundChoice.disabled && !foundChoice.selected) {\n            this._addItem(foundChoice, true, userTriggered);\n            return true;\n        }\n        return false;\n    };\n    Choices.prototype._generatePlaceholderValue = function () {\n        var config = this.config;\n        if (!config.placeholder) {\n            return null;\n        }\n        if (this._hasNonChoicePlaceholder) {\n            return config.placeholderValue;\n        }\n        if (this._isSelectElement) {\n            var placeholderOption = this.passedElement.placeholderOption;\n            return placeholderOption ? placeholderOption.text : null;\n        }\n        return null;\n    };\n    Choices.prototype._warnChoicesInitFailed = function (caller) {\n        if (this.config.silent) {\n            return;\n        }\n        if (!this.initialised) {\n            throw new TypeError(\"\".concat(caller, \" called on a non-initialised instance of Choices\"));\n        }\n        else if (!this.initialisedOK) {\n            throw new TypeError(\"\".concat(caller, \" called for an element which has multiple instances of Choices initialised on it\"));\n        }\n    };\n    Choices.version = '11.2.1';\n    return Choices;\n}());\n\nexport { Choices as default };\n"
  },
  {
    "path": "public/assets/scripts/choices.search-prefix.js",
    "content": "/*! choices.js v11.2.1 | © 2026 Josh Johnson | https://github.com/Choices-js/Choices#readme */\n\n(function (global, factory) {\n    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :\n    typeof define === 'function' && define.amd ? define(factory) :\n    (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Choices = factory());\n})(this, (function () { 'use strict';\n\n    /******************************************************************************\n    Copyright (c) Microsoft Corporation.\n\n    Permission to use, copy, modify, and/or distribute this software for any\n    purpose with or without fee is hereby granted.\n\n    THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\n    REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\n    AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\n    INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\n    LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\n    OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\n    PERFORMANCE OF THIS SOFTWARE.\n    ***************************************************************************** */\n    /* global Reflect, Promise, SuppressedError, Symbol */\n\n    var extendStatics = function (d, b) {\n      extendStatics = Object.setPrototypeOf || {\n        __proto__: []\n      } instanceof Array && function (d, b) {\n        d.__proto__ = b;\n      } || function (d, b) {\n        for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p];\n      };\n      return extendStatics(d, b);\n    };\n    function __extends(d, b) {\n      if (typeof b !== \"function\" && b !== null) throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\n      extendStatics(d, b);\n      function __() {\n        this.constructor = d;\n      }\n      d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\n    }\n    var __assign = function () {\n      __assign = Object.assign || function __assign(t) {\n        for (var s, i = 1, n = arguments.length; i < n; i++) {\n          s = arguments[i];\n          for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\n        }\n        return t;\n      };\n      return __assign.apply(this, arguments);\n    };\n    typeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\n      var e = new Error(message);\n      return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\n    };\n\n    var ActionType = {\n        ADD_CHOICE: 'ADD_CHOICE',\n        REMOVE_CHOICE: 'REMOVE_CHOICE',\n        FILTER_CHOICES: 'FILTER_CHOICES',\n        ACTIVATE_CHOICES: 'ACTIVATE_CHOICES',\n        CLEAR_CHOICES: 'CLEAR_CHOICES',\n        ADD_GROUP: 'ADD_GROUP',\n        ADD_ITEM: 'ADD_ITEM',\n        REMOVE_ITEM: 'REMOVE_ITEM',\n        HIGHLIGHT_ITEM: 'HIGHLIGHT_ITEM',\n    };\n\n    var EventType = {\n        showDropdown: 'showDropdown',\n        hideDropdown: 'hideDropdown',\n        change: 'change',\n        choice: 'choice',\n        search: 'search',\n        addItem: 'addItem',\n        removeItem: 'removeItem',\n        highlightItem: 'highlightItem',\n        highlightChoice: 'highlightChoice',\n        unhighlightItem: 'unhighlightItem',\n    };\n\n    var KeyCodeMap = {\n        TAB_KEY: 9,\n        SHIFT_KEY: 16,\n        BACK_KEY: 46,\n        DELETE_KEY: 8,\n        ENTER_KEY: 13,\n        A_KEY: 65,\n        ESC_KEY: 27,\n        UP_KEY: 38,\n        DOWN_KEY: 40,\n        PAGE_UP_KEY: 33,\n        PAGE_DOWN_KEY: 34,\n    };\n\n    var ObjectsInConfig = ['fuseOptions', 'classNames'];\n\n    var PassedElementTypes = {\n        Text: 'text',\n        SelectOne: 'select-one',\n        SelectMultiple: 'select-multiple',\n    };\n\n    var addChoice = function (choice) { return ({\n        type: ActionType.ADD_CHOICE,\n        choice: choice,\n    }); };\n    var removeChoice = function (choice) { return ({\n        type: ActionType.REMOVE_CHOICE,\n        choice: choice,\n    }); };\n    var filterChoices = function (results) { return ({\n        type: ActionType.FILTER_CHOICES,\n        results: results,\n    }); };\n    var activateChoices = function (active) {\n        return ({\n            type: ActionType.ACTIVATE_CHOICES,\n            active: active,\n        });\n    };\n\n    var addGroup = function (group) { return ({\n        type: ActionType.ADD_GROUP,\n        group: group,\n    }); };\n\n    var addItem = function (item) { return ({\n        type: ActionType.ADD_ITEM,\n        item: item,\n    }); };\n    var removeItem$1 = function (item) { return ({\n        type: ActionType.REMOVE_ITEM,\n        item: item,\n    }); };\n    var highlightItem = function (item, highlighted) { return ({\n        type: ActionType.HIGHLIGHT_ITEM,\n        item: item,\n        highlighted: highlighted,\n    }); };\n\n    var getRandomNumber = function (min, max) { return Math.floor(Math.random() * (max - min) + min); };\n    var generateChars = function (length) {\n        return Array.from({ length: length }, function () { return getRandomNumber(0, 36).toString(36); }).join('');\n    };\n    var generateId = function (element, prefix) {\n        var id = element.id || (element.name && \"\".concat(element.name, \"-\").concat(generateChars(2))) || generateChars(4);\n        id = id.replace(/(:|\\.|\\[|\\]|,)/g, '');\n        id = \"\".concat(prefix, \"-\").concat(id);\n        return id;\n    };\n    var getAdjacentEl = function (startEl, selector, direction) {\n        if (direction === void 0) { direction = 1; }\n        var prop = \"\".concat(direction > 0 ? 'next' : 'previous', \"ElementSibling\");\n        var sibling = startEl[prop];\n        while (sibling) {\n            if (sibling.matches(selector)) {\n                return sibling;\n            }\n            sibling = sibling[prop];\n        }\n        return null;\n    };\n    var isScrolledIntoView = function (element, parent, direction) {\n        if (direction === void 0) { direction = 1; }\n        var isVisible;\n        if (direction > 0) {\n            // In view from bottom\n            isVisible = parent.scrollTop + parent.offsetHeight >= element.offsetTop + element.offsetHeight;\n        }\n        else {\n            // In view from top\n            isVisible = element.offsetTop >= parent.scrollTop;\n        }\n        return isVisible;\n    };\n    var sanitise = function (value) {\n        if (typeof value !== 'string') {\n            if (value === null || value === undefined) {\n                return '';\n            }\n            if (typeof value === 'object') {\n                if ('raw' in value) {\n                    return sanitise(value.raw);\n                }\n                if ('trusted' in value) {\n                    return value.trusted;\n                }\n            }\n            return value;\n        }\n        return value\n            .replace(/&/g, '&amp;')\n            .replace(/>/g, '&gt;')\n            .replace(/</g, '&lt;')\n            .replace(/'/g, '&#039;')\n            .replace(/\"/g, '&quot;');\n    };\n    var strToEl = (function () {\n        var tmpEl = document.createElement('div');\n        return function (str) {\n            tmpEl.innerHTML = str.trim();\n            var firstChild = tmpEl.children[0];\n            while (tmpEl.firstChild) {\n                tmpEl.removeChild(tmpEl.firstChild);\n            }\n            return firstChild;\n        };\n    })();\n    var resolveStringFunction = function (fn) {\n        return typeof fn === 'function' ? fn() : fn;\n    };\n    var unwrapStringForRaw = function (s) {\n        if (typeof s === 'string') {\n            return s;\n        }\n        if (typeof s === 'object') {\n            if ('trusted' in s) {\n                return s.trusted;\n            }\n            if ('raw' in s) {\n                return s.raw;\n            }\n        }\n        return '';\n    };\n    var unwrapStringForEscaped = function (s) {\n        if (typeof s === 'string') {\n            return s;\n        }\n        if (typeof s === 'object') {\n            if ('escaped' in s) {\n                return s.escaped;\n            }\n            if ('trusted' in s) {\n                return s.trusted;\n            }\n        }\n        return '';\n    };\n    var getChoiceForOutput = function (choice, keyCode) {\n        return {\n            id: choice.id,\n            highlighted: choice.highlighted,\n            labelClass: choice.labelClass,\n            labelDescription: unwrapStringForRaw(choice.labelDescription),\n            customProperties: choice.customProperties,\n            disabled: choice.disabled,\n            active: choice.active,\n            label: choice.label,\n            placeholder: choice.placeholder,\n            value: choice.value,\n            groupValue: choice.group ? choice.group.label : undefined,\n            element: choice.element,\n            keyCode: keyCode,\n        };\n    };\n    var resolveNoticeFunction = function (fn, value, item) {\n        return typeof fn === 'function' ? fn(sanitise(value), unwrapStringForRaw(value), item) : fn;\n    };\n    var escapeForTemplate = function (allowHTML, s) {\n        return allowHTML ? unwrapStringForEscaped(s) : sanitise(s);\n    };\n    var setElementHtml = function (el, allowHtml, html) {\n        el.innerHTML = escapeForTemplate(allowHtml, html);\n    };\n    var sortByAlpha = function (_a, _b) {\n        var value = _a.value, _c = _a.label, label = _c === void 0 ? value : _c;\n        var value2 = _b.value, _d = _b.label, label2 = _d === void 0 ? value2 : _d;\n        return unwrapStringForRaw(label).localeCompare(unwrapStringForRaw(label2), [], {\n            sensitivity: 'base',\n            ignorePunctuation: true,\n            numeric: true,\n        });\n    };\n    var sortByRank = function (a, b) {\n        return a.rank - b.rank;\n    };\n    var dispatchEvent = function (element, type, customArgs) {\n        if (customArgs === void 0) { customArgs = null; }\n        var event = new CustomEvent(type, {\n            detail: customArgs,\n            bubbles: true,\n            cancelable: true,\n        });\n        return element.dispatchEvent(event);\n    };\n    /**\n     * Returns an array of keys present on the first but missing on the second object\n     */\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    var diff = function (a, b) {\n        var aKeys = Object.keys(a).sort();\n        var bKeys = Object.keys(b).sort();\n        return aKeys.filter(function (i) { return bKeys.indexOf(i) < 0; });\n    };\n    var getClassNames = function (ClassNames) {\n        return Array.isArray(ClassNames) ? ClassNames : [ClassNames];\n    };\n    var getClassNamesSelector = function (option) {\n        if (option && Array.isArray(option)) {\n            return option\n                .map(function (item) {\n                return \".\".concat(item);\n            })\n                .join('');\n        }\n        return \".\".concat(option);\n    };\n    var addClassesToElement = function (element, className) {\n        var _a;\n        (_a = element.classList).add.apply(_a, getClassNames(className));\n    };\n    var removeClassesFromElement = function (element, className) {\n        var _a;\n        (_a = element.classList).remove.apply(_a, getClassNames(className));\n    };\n    var parseCustomProperties = function (customProperties) {\n        if (typeof customProperties !== 'undefined') {\n            try {\n                return JSON.parse(customProperties);\n            }\n            catch (e) {\n                return customProperties;\n            }\n        }\n        return {};\n    };\n    var updateClassList = function (item, add, remove) {\n        var itemEl = item.itemEl;\n        if (itemEl) {\n            removeClassesFromElement(itemEl, remove);\n            addClassesToElement(itemEl, add);\n        }\n    };\n\n    var Dropdown = /** @class */ (function () {\n        function Dropdown(_a) {\n            var element = _a.element, type = _a.type, classNames = _a.classNames;\n            this.element = element;\n            this.classNames = classNames;\n            this.type = type;\n            this.isActive = false;\n        }\n        /**\n         * Show dropdown to user by adding active state class\n         */\n        Dropdown.prototype.show = function () {\n            addClassesToElement(this.element, this.classNames.activeState);\n            this.element.setAttribute('aria-expanded', 'true');\n            this.isActive = true;\n            return this;\n        };\n        /**\n         * Hide dropdown from user\n         */\n        Dropdown.prototype.hide = function () {\n            removeClassesFromElement(this.element, this.classNames.activeState);\n            this.element.setAttribute('aria-expanded', 'false');\n            this.isActive = false;\n            return this;\n        };\n        return Dropdown;\n    }());\n\n    var Container = /** @class */ (function () {\n        function Container(_a) {\n            var element = _a.element, type = _a.type, classNames = _a.classNames, position = _a.position;\n            this.element = element;\n            this.classNames = classNames;\n            this.type = type;\n            this.position = position;\n            this.isOpen = false;\n            this.isFlipped = false;\n            this.isDisabled = false;\n            this.isLoading = false;\n        }\n        /**\n         * Determine whether container should be flipped based on passed\n         * dropdown position\n         */\n        Container.prototype.shouldFlip = function (dropdownPos, dropdownHeight) {\n            // If flip is enabled and the dropdown bottom position is\n            // greater than the window height flip the dropdown.\n            var shouldFlip = false;\n            if (this.position === 'auto') {\n                shouldFlip =\n                    this.element.getBoundingClientRect().top - dropdownHeight >= 0 &&\n                        !window.matchMedia(\"(min-height: \".concat(dropdownPos + 1, \"px)\")).matches;\n            }\n            else if (this.position === 'top') {\n                shouldFlip = true;\n            }\n            return shouldFlip;\n        };\n        Container.prototype.setActiveDescendant = function (activeDescendantID) {\n            this.element.setAttribute('aria-activedescendant', activeDescendantID);\n        };\n        Container.prototype.removeActiveDescendant = function () {\n            this.element.removeAttribute('aria-activedescendant');\n        };\n        Container.prototype.open = function (dropdownPos, dropdownHeight) {\n            addClassesToElement(this.element, this.classNames.openState);\n            this.element.setAttribute('aria-expanded', 'true');\n            this.isOpen = true;\n            if (this.shouldFlip(dropdownPos, dropdownHeight)) {\n                addClassesToElement(this.element, this.classNames.flippedState);\n                this.isFlipped = true;\n            }\n        };\n        Container.prototype.close = function () {\n            removeClassesFromElement(this.element, this.classNames.openState);\n            this.element.setAttribute('aria-expanded', 'false');\n            this.removeActiveDescendant();\n            this.isOpen = false;\n            // A dropdown flips if it does not have space within the page\n            if (this.isFlipped) {\n                removeClassesFromElement(this.element, this.classNames.flippedState);\n                this.isFlipped = false;\n            }\n        };\n        Container.prototype.addFocusState = function () {\n            addClassesToElement(this.element, this.classNames.focusState);\n        };\n        Container.prototype.removeFocusState = function () {\n            removeClassesFromElement(this.element, this.classNames.focusState);\n        };\n        Container.prototype.addInvalidState = function () {\n            addClassesToElement(this.element, this.classNames.invalidState);\n        };\n        Container.prototype.removeInvalidState = function () {\n            removeClassesFromElement(this.element, this.classNames.invalidState);\n        };\n        Container.prototype.enable = function () {\n            removeClassesFromElement(this.element, this.classNames.disabledState);\n            this.element.removeAttribute('aria-disabled');\n            if (this.type === PassedElementTypes.SelectOne) {\n                this.element.setAttribute('tabindex', '0');\n            }\n            this.isDisabled = false;\n        };\n        Container.prototype.disable = function () {\n            addClassesToElement(this.element, this.classNames.disabledState);\n            this.element.setAttribute('aria-disabled', 'true');\n            if (this.type === PassedElementTypes.SelectOne) {\n                this.element.setAttribute('tabindex', '-1');\n            }\n            this.isDisabled = true;\n        };\n        Container.prototype.wrap = function (element) {\n            var el = this.element;\n            var parentNode = element.parentNode;\n            if (parentNode) {\n                if (element.nextSibling) {\n                    parentNode.insertBefore(el, element.nextSibling);\n                }\n                else {\n                    parentNode.appendChild(el);\n                }\n            }\n            el.appendChild(element);\n        };\n        Container.prototype.unwrap = function (element) {\n            var el = this.element;\n            var parentNode = el.parentNode;\n            if (parentNode) {\n                // Move passed element outside this element\n                parentNode.insertBefore(element, el);\n                // Remove this element\n                parentNode.removeChild(el);\n            }\n        };\n        Container.prototype.addLoadingState = function () {\n            addClassesToElement(this.element, this.classNames.loadingState);\n            this.element.setAttribute('aria-busy', 'true');\n            this.isLoading = true;\n        };\n        Container.prototype.removeLoadingState = function () {\n            removeClassesFromElement(this.element, this.classNames.loadingState);\n            this.element.removeAttribute('aria-busy');\n            this.isLoading = false;\n        };\n        return Container;\n    }());\n\n    var Input = /** @class */ (function () {\n        function Input(_a) {\n            var element = _a.element, type = _a.type, classNames = _a.classNames, preventPaste = _a.preventPaste;\n            this.element = element;\n            this.type = type;\n            this.classNames = classNames;\n            this.preventPaste = preventPaste;\n            this.isFocussed = this.element.isEqualNode(document.activeElement);\n            this.isDisabled = element.disabled;\n            this._onPaste = this._onPaste.bind(this);\n            this._onInput = this._onInput.bind(this);\n            this._onFocus = this._onFocus.bind(this);\n            this._onBlur = this._onBlur.bind(this);\n        }\n        Object.defineProperty(Input.prototype, \"placeholder\", {\n            set: function (placeholder) {\n                this.element.placeholder = placeholder;\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(Input.prototype, \"value\", {\n            get: function () {\n                return this.element.value;\n            },\n            set: function (value) {\n                this.element.value = value;\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Input.prototype.addEventListeners = function () {\n            var el = this.element;\n            el.addEventListener('paste', this._onPaste);\n            el.addEventListener('input', this._onInput, {\n                passive: true,\n            });\n            el.addEventListener('focus', this._onFocus, {\n                passive: true,\n            });\n            el.addEventListener('blur', this._onBlur, {\n                passive: true,\n            });\n        };\n        Input.prototype.removeEventListeners = function () {\n            var el = this.element;\n            el.removeEventListener('input', this._onInput);\n            el.removeEventListener('paste', this._onPaste);\n            el.removeEventListener('focus', this._onFocus);\n            el.removeEventListener('blur', this._onBlur);\n        };\n        Input.prototype.enable = function () {\n            var el = this.element;\n            el.removeAttribute('disabled');\n            this.isDisabled = false;\n        };\n        Input.prototype.disable = function () {\n            var el = this.element;\n            el.setAttribute('disabled', '');\n            this.isDisabled = true;\n        };\n        Input.prototype.focus = function () {\n            if (!this.isFocussed) {\n                this.element.focus();\n            }\n        };\n        Input.prototype.blur = function () {\n            if (this.isFocussed) {\n                this.element.blur();\n            }\n        };\n        Input.prototype.clear = function (setWidth) {\n            if (setWidth === void 0) { setWidth = true; }\n            this.element.value = '';\n            if (setWidth) {\n                this.setWidth();\n            }\n            return this;\n        };\n        /**\n         * Set the correct input width based on placeholder\n         * value or input value\n         */\n        Input.prototype.setWidth = function () {\n            // Resize input to contents or placeholder\n            var element = this.element;\n            element.style.minWidth = \"\".concat(element.placeholder.length + 1, \"ch\");\n            element.style.width = \"\".concat(element.value.length + 1, \"ch\");\n        };\n        Input.prototype.setActiveDescendant = function (activeDescendantID) {\n            this.element.setAttribute('aria-activedescendant', activeDescendantID);\n        };\n        Input.prototype.removeActiveDescendant = function () {\n            this.element.removeAttribute('aria-activedescendant');\n        };\n        Input.prototype._onInput = function () {\n            if (this.type !== PassedElementTypes.SelectOne) {\n                this.setWidth();\n            }\n        };\n        Input.prototype._onPaste = function (event) {\n            if (this.preventPaste) {\n                event.preventDefault();\n            }\n        };\n        Input.prototype._onFocus = function () {\n            this.isFocussed = true;\n        };\n        Input.prototype._onBlur = function () {\n            this.isFocussed = false;\n        };\n        return Input;\n    }());\n\n    var SCROLLING_SPEED = 4;\n\n    var List = /** @class */ (function () {\n        function List(_a) {\n            var element = _a.element;\n            this.element = element;\n            this.scrollPos = this.element.scrollTop;\n            this.height = this.element.offsetHeight;\n        }\n        List.prototype.prepend = function (node) {\n            var child = this.element.firstElementChild;\n            if (child) {\n                this.element.insertBefore(node, child);\n            }\n            else {\n                this.element.append(node);\n            }\n        };\n        List.prototype.scrollToTop = function () {\n            this.element.scrollTop = 0;\n        };\n        List.prototype.scrollToChildElement = function (element, direction) {\n            var _this = this;\n            if (!element) {\n                return;\n            }\n            var listHeight = this.element.offsetHeight;\n            // Scroll position of dropdown\n            var listScrollPosition = this.element.scrollTop + listHeight;\n            var elementHeight = element.offsetHeight;\n            // Distance from bottom of element to top of parent\n            var elementPos = element.offsetTop + elementHeight;\n            // Difference between the element and scroll position\n            var destination = direction > 0 ? this.element.scrollTop + elementPos - listScrollPosition : element.offsetTop;\n            requestAnimationFrame(function () {\n                _this._animateScroll(destination, direction);\n            });\n        };\n        List.prototype._scrollDown = function (scrollPos, strength, destination) {\n            var easing = (destination - scrollPos) / strength;\n            var distance = easing > 1 ? easing : 1;\n            this.element.scrollTop = scrollPos + distance;\n        };\n        List.prototype._scrollUp = function (scrollPos, strength, destination) {\n            var easing = (scrollPos - destination) / strength;\n            var distance = easing > 1 ? easing : 1;\n            this.element.scrollTop = scrollPos - distance;\n        };\n        List.prototype._animateScroll = function (destination, direction) {\n            var _this = this;\n            var strength = SCROLLING_SPEED;\n            var choiceListScrollTop = this.element.scrollTop;\n            var continueAnimation = false;\n            if (direction > 0) {\n                this._scrollDown(choiceListScrollTop, strength, destination);\n                if (choiceListScrollTop < destination) {\n                    continueAnimation = true;\n                }\n            }\n            else {\n                this._scrollUp(choiceListScrollTop, strength, destination);\n                if (choiceListScrollTop > destination) {\n                    continueAnimation = true;\n                }\n            }\n            if (continueAnimation) {\n                requestAnimationFrame(function () {\n                    _this._animateScroll(destination, direction);\n                });\n            }\n        };\n        return List;\n    }());\n\n    var WrappedElement = /** @class */ (function () {\n        function WrappedElement(_a) {\n            var element = _a.element, classNames = _a.classNames;\n            this.element = element;\n            this.classNames = classNames;\n            this.isDisabled = false;\n        }\n        Object.defineProperty(WrappedElement.prototype, \"isActive\", {\n            get: function () {\n                return this.element.dataset.choice === 'active';\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(WrappedElement.prototype, \"dir\", {\n            get: function () {\n                return this.element.dir;\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(WrappedElement.prototype, \"value\", {\n            get: function () {\n                return this.element.value;\n            },\n            set: function (value) {\n                this.element.setAttribute('value', value);\n                this.element.value = value;\n            },\n            enumerable: false,\n            configurable: true\n        });\n        WrappedElement.prototype.conceal = function () {\n            var el = this.element;\n            // Hide passed input\n            addClassesToElement(el, this.classNames.input);\n            el.hidden = true;\n            // Remove element from tab index\n            el.tabIndex = -1;\n            // Backup original styles if any\n            var origStyle = el.getAttribute('style');\n            if (origStyle) {\n                el.setAttribute('data-choice-orig-style', origStyle);\n            }\n            el.setAttribute('data-choice', 'active');\n        };\n        WrappedElement.prototype.reveal = function () {\n            var el = this.element;\n            // Reinstate passed element\n            removeClassesFromElement(el, this.classNames.input);\n            el.hidden = false;\n            el.removeAttribute('tabindex');\n            // Recover original styles if any\n            var origStyle = el.getAttribute('data-choice-orig-style');\n            if (origStyle) {\n                el.removeAttribute('data-choice-orig-style');\n                el.setAttribute('style', origStyle);\n            }\n            else {\n                el.removeAttribute('style');\n            }\n            el.removeAttribute('data-choice');\n        };\n        WrappedElement.prototype.enable = function () {\n            this.element.removeAttribute('disabled');\n            this.element.disabled = false;\n            this.isDisabled = false;\n        };\n        WrappedElement.prototype.disable = function () {\n            this.element.setAttribute('disabled', '');\n            this.element.disabled = true;\n            this.isDisabled = true;\n        };\n        WrappedElement.prototype.triggerEvent = function (eventType, data) {\n            dispatchEvent(this.element, eventType, data || {});\n        };\n        return WrappedElement;\n    }());\n\n    var WrappedInput = /** @class */ (function (_super) {\n        __extends(WrappedInput, _super);\n        function WrappedInput() {\n            return _super !== null && _super.apply(this, arguments) || this;\n        }\n        return WrappedInput;\n    }(WrappedElement));\n\n    var coerceBool = function (arg, defaultValue) {\n        if (defaultValue === void 0) { defaultValue = true; }\n        return typeof arg === 'undefined' ? defaultValue : !!arg;\n    };\n    var stringToHtmlClass = function (input) {\n        if (typeof input === 'string') {\n            // eslint-disable-next-line no-param-reassign\n            input = input.split(' ').filter(function (s) { return s.length; });\n        }\n        if (Array.isArray(input) && input.length) {\n            return input;\n        }\n        return undefined;\n    };\n    var mapInputToChoice = function (value, allowGroup, allowRawString) {\n        if (allowRawString === void 0) { allowRawString = true; }\n        if (typeof value === 'string') {\n            var sanitisedValue = sanitise(value);\n            var userValue = allowRawString || sanitisedValue === value ? value : { escaped: sanitisedValue, raw: value };\n            var result_1 = mapInputToChoice({\n                value: value,\n                label: userValue,\n                selected: true,\n            }, false);\n            return result_1;\n        }\n        var groupOrChoice = value;\n        if ('choices' in groupOrChoice) {\n            if (!allowGroup) {\n                // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/optgroup\n                throw new TypeError(\"optGroup is not allowed\");\n            }\n            var group = groupOrChoice;\n            var choices = group.choices.map(function (e) { return mapInputToChoice(e, false); });\n            var result_2 = {\n                id: 0, // actual ID will be assigned during _addGroup\n                label: unwrapStringForRaw(group.label) || group.value,\n                active: !!choices.length,\n                disabled: !!group.disabled,\n                choices: choices,\n            };\n            return result_2;\n        }\n        var choice = groupOrChoice;\n        var result = {\n            id: 0, // actual ID will be assigned during _addChoice\n            group: null, // actual group will be assigned during _addGroup but before _addChoice\n            score: 0, // used in search\n            rank: 0, // used in search, stable sort order\n            value: choice.value,\n            label: choice.label || choice.value,\n            active: coerceBool(choice.active),\n            selected: coerceBool(choice.selected, false),\n            disabled: coerceBool(choice.disabled, false),\n            placeholder: coerceBool(choice.placeholder, false),\n            highlighted: false,\n            labelClass: stringToHtmlClass(choice.labelClass),\n            labelDescription: choice.labelDescription,\n            customProperties: choice.customProperties,\n        };\n        return result;\n    };\n\n    var isHtmlInputElement = function (e) { return e.tagName === 'INPUT'; };\n    var isHtmlSelectElement = function (e) { return e.tagName === 'SELECT'; };\n    var isHtmlOption = function (e) { return e.tagName === 'OPTION'; };\n    var isHtmlOptgroup = function (e) { return e.tagName === 'OPTGROUP'; };\n\n    var WrappedSelect = /** @class */ (function (_super) {\n        __extends(WrappedSelect, _super);\n        function WrappedSelect(_a) {\n            var element = _a.element, classNames = _a.classNames, template = _a.template, extractPlaceholder = _a.extractPlaceholder;\n            var _this = _super.call(this, { element: element, classNames: classNames }) || this;\n            _this.template = template;\n            _this.extractPlaceholder = extractPlaceholder;\n            return _this;\n        }\n        Object.defineProperty(WrappedSelect.prototype, \"placeholderOption\", {\n            get: function () {\n                return (this.element.querySelector('option[value=\"\"]') ||\n                    // Backward compatibility layer for the non-standard placeholder attribute supported in older versions.\n                    this.element.querySelector('option[placeholder]'));\n            },\n            enumerable: false,\n            configurable: true\n        });\n        WrappedSelect.prototype.addOptions = function (choices) {\n            var _this = this;\n            var fragment = document.createDocumentFragment();\n            choices.forEach(function (obj) {\n                var choice = obj;\n                if (choice.element) {\n                    return;\n                }\n                var option = _this.template(choice);\n                fragment.appendChild(option);\n                choice.element = option;\n            });\n            this.element.appendChild(fragment);\n        };\n        WrappedSelect.prototype.optionsAsChoices = function () {\n            var _this = this;\n            var choices = [];\n            this.element.querySelectorAll(':scope > option, :scope > optgroup').forEach(function (e) {\n                if (isHtmlOption(e)) {\n                    choices.push(_this._optionToChoice(e));\n                }\n                else if (isHtmlOptgroup(e)) {\n                    choices.push(_this._optgroupToChoice(e));\n                }\n                // todo: hr as empty optgroup, requires displaying empty opt-groups to be useful\n            });\n            return choices;\n        };\n        // eslint-disable-next-line class-methods-use-this\n        WrappedSelect.prototype._optionToChoice = function (option) {\n            // option.value returns the label if there is no value attribute, which can break legacy placeholder attribute support\n            if (!option.hasAttribute('value') && option.hasAttribute('placeholder')) {\n                option.setAttribute('value', '');\n                option.value = '';\n            }\n            return {\n                id: 0,\n                group: null,\n                score: 0,\n                rank: 0,\n                value: option.value,\n                // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/option\n                // This attribute is text for the label indicating the meaning of the option. If the `label` attribute isn't defined, its value is that of the element text content (ie `innerText`).\n                label: option.label,\n                element: option,\n                active: true,\n                // this returns true if nothing is selected on initial load, which will break placeholder support\n                selected: this.extractPlaceholder ? option.selected : option.hasAttribute('selected'),\n                disabled: option.disabled,\n                highlighted: false,\n                placeholder: this.extractPlaceholder && (!option.value || option.hasAttribute('placeholder')),\n                labelClass: typeof option.dataset.labelClass !== 'undefined' ? stringToHtmlClass(option.dataset.labelClass) : undefined,\n                labelDescription: typeof option.dataset.labelDescription !== 'undefined'\n                    ? { trusted: option.dataset.labelDescription }\n                    : undefined,\n                customProperties: parseCustomProperties(option.dataset.customProperties),\n            };\n        };\n        WrappedSelect.prototype._optgroupToChoice = function (optgroup) {\n            var _this = this;\n            var options = optgroup.querySelectorAll('option');\n            var choices = Array.from(options).map(function (option) { return _this._optionToChoice(option); });\n            return {\n                id: 0,\n                label: optgroup.label || '',\n                element: optgroup,\n                active: !!choices.length,\n                disabled: optgroup.disabled,\n                choices: choices,\n            };\n        };\n        return WrappedSelect;\n    }(WrappedElement));\n\n    var DEFAULT_CLASSNAMES = {\n        containerOuter: ['choices'],\n        containerInner: ['choices__inner'],\n        input: ['choices__input'],\n        inputCloned: ['choices__input--cloned'],\n        list: ['choices__list'],\n        listItems: ['choices__list--multiple'],\n        listSingle: ['choices__list--single'],\n        listDropdown: ['choices__list--dropdown'],\n        item: ['choices__item'],\n        itemSelectable: ['choices__item--selectable'],\n        itemDisabled: ['choices__item--disabled'],\n        itemChoice: ['choices__item--choice'],\n        description: ['choices__description'],\n        placeholder: ['choices__placeholder'],\n        group: ['choices__group'],\n        groupHeading: ['choices__heading'],\n        button: ['choices__button'],\n        activeState: ['is-active'],\n        focusState: ['is-focused'],\n        openState: ['is-open'],\n        disabledState: ['is-disabled'],\n        highlightedState: ['is-highlighted'],\n        selectedState: ['is-selected'],\n        flippedState: ['is-flipped'],\n        loadingState: ['is-loading'],\n        invalidState: ['is-invalid'],\n        notice: ['choices__notice'],\n        addChoice: ['choices__item--selectable', 'add-choice'],\n        noResults: ['has-no-results'],\n        noChoices: ['has-no-choices'],\n    };\n    var DEFAULT_CONFIG = {\n        items: [],\n        choices: [],\n        silent: false,\n        renderChoiceLimit: -1,\n        maxItemCount: -1,\n        closeDropdownOnSelect: 'auto',\n        singleModeForMultiSelect: false,\n        addChoices: false,\n        addItems: true,\n        addItemFilter: function (value) { return !!value && value !== ''; },\n        removeItems: true,\n        removeItemButton: false,\n        removeItemButtonAlignLeft: false,\n        editItems: false,\n        allowHTML: false,\n        allowHtmlUserInput: false,\n        duplicateItemsAllowed: true,\n        delimiter: ',',\n        paste: true,\n        searchEnabled: true,\n        searchChoices: true,\n        searchDisabledChoices: false,\n        searchFloor: 1,\n        searchResultLimit: 4,\n        searchFields: ['label', 'value'],\n        position: 'auto',\n        resetScrollPosition: true,\n        shouldSort: true,\n        shouldSortItems: false,\n        sorter: sortByAlpha,\n        shadowRoot: null,\n        placeholder: true,\n        placeholderValue: null,\n        searchPlaceholderValue: null,\n        prependValue: null,\n        appendValue: null,\n        renderSelectedChoices: 'auto',\n        searchRenderSelectedChoices: true,\n        loadingText: 'Loading...',\n        noResultsText: 'No results found',\n        noChoicesText: 'No choices to choose from',\n        itemSelectText: 'Press to select',\n        uniqueItemText: 'Only unique values can be added',\n        customAddItemText: 'Only values matching specific conditions can be added',\n        addItemText: function (value) { return \"Press Enter to add <b>\\\"\".concat(value, \"\\\"</b>\"); },\n        removeItemIconText: function () { return \"Remove item\"; },\n        removeItemLabelText: function (value, _valueRaw, i) {\n            return \"Remove item: \".concat(i ? sanitise(i.label) : value);\n        },\n        maxItemText: function (maxItemCount) { return \"Only \".concat(maxItemCount, \" values can be added\"); },\n        valueComparer: function (value1, value2) { return value1 === value2; },\n        fuseOptions: {\n            includeScore: true,\n        },\n        labelId: '',\n        callbackOnInit: null,\n        callbackOnCreateTemplates: null,\n        classNames: DEFAULT_CLASSNAMES,\n        appendGroupInSearch: false,\n    };\n\n    var removeItem = function (item) {\n        var itemEl = item.itemEl;\n        if (itemEl) {\n            itemEl.remove();\n            item.itemEl = undefined;\n        }\n    };\n    function items(s, action, context) {\n        var state = s;\n        var update = true;\n        switch (action.type) {\n            case ActionType.ADD_ITEM: {\n                action.item.selected = true;\n                var el = action.item.element;\n                if (el) {\n                    el.selected = true;\n                    el.setAttribute('selected', '');\n                }\n                state.push(action.item);\n                break;\n            }\n            case ActionType.REMOVE_ITEM: {\n                action.item.selected = false;\n                var el = action.item.element;\n                if (el) {\n                    el.selected = false;\n                    el.removeAttribute('selected');\n                    // For a select-one, if all options are deselected, the first item is selected. To set a black value, select.value needs to be set\n                    var select = el.parentElement;\n                    if (select && isHtmlSelectElement(select) && select.type === PassedElementTypes.SelectOne) {\n                        select.value = '';\n                    }\n                }\n                // this is mixing concerns, but this is *so much faster*\n                removeItem(action.item);\n                state = state.filter(function (choice) { return choice.id !== action.item.id; });\n                break;\n            }\n            case ActionType.REMOVE_CHOICE: {\n                removeItem(action.choice);\n                state = state.filter(function (item) { return item.id !== action.choice.id; });\n                break;\n            }\n            case ActionType.HIGHLIGHT_ITEM: {\n                var highlighted = action.highlighted;\n                var item = state.find(function (obj) { return obj.id === action.item.id; });\n                if (item && item.highlighted !== highlighted) {\n                    item.highlighted = highlighted;\n                    if (context) {\n                        updateClassList(item, highlighted ? context.classNames.highlightedState : context.classNames.selectedState, highlighted ? context.classNames.selectedState : context.classNames.highlightedState);\n                    }\n                }\n                break;\n            }\n            default: {\n                update = false;\n                break;\n            }\n        }\n        return { state: state, update: update };\n    }\n\n    function groups(s, action) {\n        var state = s;\n        var update = true;\n        switch (action.type) {\n            case ActionType.ADD_GROUP: {\n                state.push(action.group);\n                break;\n            }\n            case ActionType.CLEAR_CHOICES: {\n                state = [];\n                break;\n            }\n            default: {\n                update = false;\n                break;\n            }\n        }\n        return { state: state, update: update };\n    }\n\n    /* eslint-disable */\n    function choices(s, action, context) {\n        var state = s;\n        var update = true;\n        switch (action.type) {\n            case ActionType.ADD_CHOICE: {\n                state.push(action.choice);\n                break;\n            }\n            case ActionType.REMOVE_CHOICE: {\n                action.choice.choiceEl = undefined;\n                if (action.choice.group) {\n                    action.choice.group.choices = action.choice.group.choices.filter(function (obj) { return obj.id !== action.choice.id; });\n                }\n                state = state.filter(function (obj) { return obj.id !== action.choice.id; });\n                break;\n            }\n            case ActionType.ADD_ITEM:\n            case ActionType.REMOVE_ITEM: {\n                action.item.choiceEl = undefined;\n                break;\n            }\n            case ActionType.FILTER_CHOICES: {\n                // avoid O(n^2) algorithm complexity when searching/filtering choices\n                var scoreLookup_1 = [];\n                action.results.forEach(function (result) {\n                    scoreLookup_1[result.item.id] = result;\n                });\n                state.forEach(function (choice) {\n                    var result = scoreLookup_1[choice.id];\n                    if (result !== undefined) {\n                        choice.score = result.score;\n                        choice.rank = result.rank;\n                        choice.active = true;\n                    }\n                    else {\n                        choice.score = 0;\n                        choice.rank = 0;\n                        choice.active = false;\n                    }\n                    if (context && context.appendGroupInSearch) {\n                        choice.choiceEl = undefined;\n                    }\n                });\n                break;\n            }\n            case ActionType.ACTIVATE_CHOICES: {\n                state.forEach(function (choice) {\n                    choice.active = action.active;\n                    if (context && context.appendGroupInSearch) {\n                        choice.choiceEl = undefined;\n                    }\n                });\n                break;\n            }\n            case ActionType.CLEAR_CHOICES: {\n                state = [];\n                break;\n            }\n            default: {\n                update = false;\n                break;\n            }\n        }\n        return { state: state, update: update };\n    }\n\n    var reducers = {\n        groups: groups,\n        items: items,\n        choices: choices,\n    };\n    var Store = /** @class */ (function () {\n        function Store(context) {\n            this._state = this.defaultState;\n            this._listeners = [];\n            this._txn = 0;\n            this._context = context;\n        }\n        Object.defineProperty(Store.prototype, \"defaultState\", {\n            // eslint-disable-next-line class-methods-use-this\n            get: function () {\n                return {\n                    groups: [],\n                    items: [],\n                    choices: [],\n                };\n            },\n            enumerable: false,\n            configurable: true\n        });\n        // eslint-disable-next-line class-methods-use-this\n        Store.prototype.changeSet = function (init) {\n            return {\n                groups: init,\n                items: init,\n                choices: init,\n            };\n        };\n        Store.prototype.reset = function () {\n            this._state = this.defaultState;\n            var changes = this.changeSet(true);\n            if (this._txn) {\n                this._changeSet = changes;\n            }\n            else {\n                this._listeners.forEach(function (l) { return l(changes); });\n            }\n        };\n        Store.prototype.subscribe = function (onChange) {\n            this._listeners.push(onChange);\n            return this;\n        };\n        Store.prototype.dispatch = function (action) {\n            var _this = this;\n            var state = this._state;\n            var hasChanges = false;\n            var changes = this._changeSet || this.changeSet(false);\n            Object.keys(reducers).forEach(function (key) {\n                var stateUpdate = reducers[key](state[key], action, _this._context);\n                if (stateUpdate.update) {\n                    hasChanges = true;\n                    changes[key] = true;\n                    state[key] = stateUpdate.state;\n                }\n            });\n            if (hasChanges) {\n                if (this._txn) {\n                    this._changeSet = changes;\n                }\n                else {\n                    this._listeners.forEach(function (l) { return l(changes); });\n                }\n            }\n        };\n        Store.prototype.withTxn = function (func) {\n            this._txn++;\n            try {\n                func();\n            }\n            finally {\n                this._txn = Math.max(0, this._txn - 1);\n                if (!this._txn) {\n                    var changeSet_1 = this._changeSet;\n                    if (changeSet_1) {\n                        this._changeSet = undefined;\n                        this._listeners.forEach(function (l) { return l(changeSet_1); });\n                    }\n                }\n            }\n        };\n        Object.defineProperty(Store.prototype, \"state\", {\n            /**\n             * Get store object\n             */\n            get: function () {\n                return this._state;\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(Store.prototype, \"items\", {\n            /**\n             * Get items from store\n             */\n            get: function () {\n                return this.state.items;\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(Store.prototype, \"highlightedActiveItems\", {\n            /**\n             * Get highlighted items from store\n             */\n            get: function () {\n                return this.items.filter(function (item) { return item.active && item.highlighted; });\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(Store.prototype, \"choices\", {\n            /**\n             * Get choices from store\n             */\n            get: function () {\n                return this.state.choices;\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(Store.prototype, \"activeChoices\", {\n            /**\n             * Get active choices from store\n             */\n            get: function () {\n                return this.choices.filter(function (choice) { return choice.active; });\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(Store.prototype, \"searchableChoices\", {\n            /**\n             * Get choices that can be searched (excluding placeholders or disabled choices)\n             */\n            get: function () {\n                var context = this._context;\n                return this.choices.filter(function (choice) { return !choice.placeholder && (context.searchDisabledChoices || !choice.disabled); });\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(Store.prototype, \"groups\", {\n            /**\n             * Get groups from store\n             */\n            get: function () {\n                return this.state.groups;\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Object.defineProperty(Store.prototype, \"activeGroups\", {\n            /**\n             * Get active groups from store\n             */\n            get: function () {\n                var _this = this;\n                return this.state.groups.filter(function (group) {\n                    var isActive = group.active && !group.disabled;\n                    var hasActiveOptions = _this.state.choices.some(function (choice) { return choice.active && !choice.disabled; });\n                    return isActive && hasActiveOptions;\n                }, []);\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Store.prototype.inTxn = function () {\n            return this._txn > 0;\n        };\n        /**\n         * Get single choice by it's ID\n         */\n        Store.prototype.getChoiceById = function (id) {\n            return this.activeChoices.find(function (choice) { return choice.id === id; });\n        };\n        /**\n         * Get group by group id\n         */\n        Store.prototype.getGroupById = function (id) {\n            return this.groups.find(function (group) { return group.id === id; });\n        };\n        return Store;\n    }());\n\n    var NoticeTypes = {\n        noChoices: 'no-choices',\n        noResults: 'no-results',\n        addChoice: 'add-choice',\n        generic: '',\n    };\n\n    var SearchByPrefixFilter = /** @class */ (function () {\n        function SearchByPrefixFilter(config) {\n            this._haystack = [];\n            this._fields = config.searchFields;\n        }\n        SearchByPrefixFilter.prototype.index = function (data) {\n            this._haystack = data;\n        };\n        SearchByPrefixFilter.prototype.reset = function () {\n            this._haystack = [];\n        };\n        SearchByPrefixFilter.prototype.isEmptyIndex = function () {\n            return !this._haystack.length;\n        };\n        SearchByPrefixFilter.prototype.search = function (_needle) {\n            var fields = this._fields;\n            if (!fields || !fields.length || !_needle) {\n                return [];\n            }\n            var needle = _needle.toLowerCase();\n            return this._haystack\n                .filter(function (obj) { return fields.some(function (field) { return field in obj && obj[field].toLowerCase().startsWith(needle); }); })\n                .map(function (value, index) {\n                return {\n                    item: value,\n                    score: index,\n                    rank: index + 1,\n                };\n            });\n        };\n        return SearchByPrefixFilter;\n    }());\n\n    function getSearcher(config) {\n        return new SearchByPrefixFilter(config);\n    }\n\n    /**\n     * Helpers to create HTML elements used by Choices\n     * Can be overridden by providing `callbackOnCreateTemplates` option.\n     * `Choices.defaults.templates` allows access to the default template methods from `callbackOnCreateTemplates`\n     */\n    var isEmptyObject = function (obj) {\n        // eslint-disable-next-line no-restricted-syntax\n        for (var prop in obj) {\n            if (Object.prototype.hasOwnProperty.call(obj, prop)) {\n                return false;\n            }\n        }\n        return true;\n    };\n    var assignCustomProperties = function (el, choice, withCustomProperties) {\n        var dataset = el.dataset;\n        var customProperties = choice.customProperties, labelClass = choice.labelClass, labelDescription = choice.labelDescription;\n        if (labelClass) {\n            dataset.labelClass = getClassNames(labelClass).join(' ');\n        }\n        if (labelDescription) {\n            dataset.labelDescription = unwrapStringForRaw(labelDescription);\n        }\n        if (withCustomProperties && customProperties) {\n            if (typeof customProperties === 'string') {\n                dataset.customProperties = customProperties;\n            }\n            else if (typeof customProperties === 'object' && !isEmptyObject(customProperties)) {\n                dataset.customProperties = JSON.stringify(customProperties);\n            }\n        }\n    };\n    var addAriaLabel = function (docRoot, id, element) {\n        var label = id && docRoot.querySelector(\"label[for='\".concat(id, \"']\"));\n        var text = label && label.innerText;\n        if (text) {\n            element.setAttribute('aria-label', text);\n        }\n    };\n    var templates = {\n        containerOuter: function (_a, dir, isSelectElement, isSelectOneElement, searchEnabled, passedElementType, labelId) {\n            var containerOuter = _a.classNames.containerOuter;\n            var div = document.createElement('div');\n            addClassesToElement(div, containerOuter);\n            div.dataset.type = passedElementType;\n            if (dir) {\n                div.dir = dir;\n            }\n            if (isSelectOneElement) {\n                div.tabIndex = 0;\n            }\n            if (isSelectElement) {\n                div.setAttribute('role', searchEnabled ? 'combobox' : 'listbox');\n                if (searchEnabled) {\n                    div.setAttribute('aria-autocomplete', 'list');\n                }\n                else if (!labelId) {\n                    addAriaLabel(this._docRoot, this.passedElement.element.id, div);\n                }\n                div.setAttribute('aria-haspopup', 'true');\n                div.setAttribute('aria-expanded', 'false');\n            }\n            if (labelId) {\n                div.setAttribute('aria-labelledby', labelId);\n            }\n            return div;\n        },\n        containerInner: function (_a) {\n            var containerInner = _a.classNames.containerInner;\n            var div = document.createElement('div');\n            addClassesToElement(div, containerInner);\n            return div;\n        },\n        itemList: function (_a, isSelectOneElement) {\n            var searchEnabled = _a.searchEnabled, _b = _a.classNames, list = _b.list, listSingle = _b.listSingle, listItems = _b.listItems;\n            var div = document.createElement('div');\n            addClassesToElement(div, list);\n            addClassesToElement(div, isSelectOneElement ? listSingle : listItems);\n            if (this._isSelectElement && searchEnabled) {\n                div.setAttribute('role', 'listbox');\n            }\n            return div;\n        },\n        placeholder: function (_a, value) {\n            var allowHTML = _a.allowHTML, placeholder = _a.classNames.placeholder;\n            var div = document.createElement('div');\n            addClassesToElement(div, placeholder);\n            setElementHtml(div, allowHTML, value);\n            return div;\n        },\n        item: function (_a, choice, removeItemButton) {\n            var allowHTML = _a.allowHTML, removeItemButtonAlignLeft = _a.removeItemButtonAlignLeft, removeItemIconText = _a.removeItemIconText, removeItemLabelText = _a.removeItemLabelText, _b = _a.classNames, item = _b.item, button = _b.button, highlightedState = _b.highlightedState, itemSelectable = _b.itemSelectable, placeholder = _b.placeholder;\n            var rawValue = unwrapStringForRaw(choice.value);\n            var div = document.createElement('div');\n            addClassesToElement(div, item);\n            if (choice.labelClass) {\n                var spanLabel = document.createElement('span');\n                setElementHtml(spanLabel, allowHTML, choice.label);\n                addClassesToElement(spanLabel, choice.labelClass);\n                div.appendChild(spanLabel);\n            }\n            else {\n                setElementHtml(div, allowHTML, choice.label);\n            }\n            div.dataset.item = '';\n            div.dataset.id = choice.id;\n            div.dataset.value = rawValue;\n            assignCustomProperties(div, choice, true);\n            if (choice.disabled || this.containerOuter.isDisabled) {\n                div.setAttribute('aria-disabled', 'true');\n            }\n            if (this._isSelectElement) {\n                div.setAttribute('aria-selected', 'true');\n                div.setAttribute('role', 'option');\n            }\n            if (choice.placeholder) {\n                addClassesToElement(div, placeholder);\n                div.dataset.placeholder = '';\n            }\n            addClassesToElement(div, choice.highlighted ? highlightedState : itemSelectable);\n            if (removeItemButton) {\n                if (choice.disabled) {\n                    removeClassesFromElement(div, itemSelectable);\n                }\n                div.dataset.deletable = '';\n                var removeButton = document.createElement('button');\n                removeButton.type = 'button';\n                addClassesToElement(removeButton, button);\n                var eventChoice = getChoiceForOutput(choice);\n                setElementHtml(removeButton, true, resolveNoticeFunction(removeItemIconText, choice.value, eventChoice));\n                var REMOVE_ITEM_LABEL = resolveNoticeFunction(removeItemLabelText, choice.value, eventChoice);\n                if (REMOVE_ITEM_LABEL) {\n                    removeButton.setAttribute('aria-label', REMOVE_ITEM_LABEL);\n                }\n                removeButton.dataset.button = '';\n                if (removeItemButtonAlignLeft) {\n                    div.insertAdjacentElement('afterbegin', removeButton);\n                }\n                else {\n                    div.appendChild(removeButton);\n                }\n            }\n            return div;\n        },\n        choiceList: function (_a, isSelectOneElement) {\n            var list = _a.classNames.list;\n            var div = document.createElement('div');\n            addClassesToElement(div, list);\n            if (!isSelectOneElement) {\n                div.setAttribute('aria-multiselectable', 'true');\n            }\n            div.setAttribute('role', 'listbox');\n            return div;\n        },\n        choiceGroup: function (_a, _b) {\n            var allowHTML = _a.allowHTML, _c = _a.classNames, group = _c.group, groupHeading = _c.groupHeading, itemDisabled = _c.itemDisabled;\n            var id = _b.id, label = _b.label, disabled = _b.disabled;\n            var rawLabel = unwrapStringForRaw(label);\n            var div = document.createElement('div');\n            addClassesToElement(div, group);\n            if (disabled) {\n                addClassesToElement(div, itemDisabled);\n            }\n            div.setAttribute('role', 'group');\n            div.dataset.group = '';\n            div.dataset.id = id;\n            div.dataset.value = rawLabel;\n            if (disabled) {\n                div.setAttribute('aria-disabled', 'true');\n            }\n            var heading = document.createElement('div');\n            addClassesToElement(heading, groupHeading);\n            setElementHtml(heading, allowHTML, label || '');\n            div.appendChild(heading);\n            return div;\n        },\n        choice: function (_a, choice, selectText, groupName) {\n            var allowHTML = _a.allowHTML, _b = _a.classNames, item = _b.item, itemChoice = _b.itemChoice, itemSelectable = _b.itemSelectable, selectedState = _b.selectedState, itemDisabled = _b.itemDisabled, description = _b.description, placeholder = _b.placeholder;\n            // eslint-disable-next-line prefer-destructuring\n            var label = choice.label;\n            var rawValue = unwrapStringForRaw(choice.value);\n            var div = document.createElement('div');\n            div.id = choice.elementId;\n            addClassesToElement(div, item);\n            addClassesToElement(div, itemChoice);\n            if (groupName && typeof label === 'string') {\n                label = escapeForTemplate(allowHTML, label);\n                label += \" (\".concat(groupName, \")\");\n                label = { trusted: label };\n            }\n            var describedBy = div;\n            if (choice.labelClass) {\n                var spanLabel = document.createElement('span');\n                setElementHtml(spanLabel, allowHTML, label);\n                addClassesToElement(spanLabel, choice.labelClass);\n                describedBy = spanLabel;\n                div.appendChild(spanLabel);\n            }\n            else {\n                setElementHtml(div, allowHTML, label);\n            }\n            if (choice.labelDescription) {\n                var descId = \"\".concat(choice.elementId, \"-description\");\n                describedBy.setAttribute('aria-describedby', descId);\n                var spanDesc = document.createElement('span');\n                setElementHtml(spanDesc, allowHTML, choice.labelDescription);\n                spanDesc.id = descId;\n                addClassesToElement(spanDesc, description);\n                div.appendChild(spanDesc);\n            }\n            if (choice.selected) {\n                addClassesToElement(div, selectedState);\n            }\n            if (choice.placeholder) {\n                addClassesToElement(div, placeholder);\n            }\n            div.setAttribute('role', choice.group ? 'treeitem' : 'option');\n            div.dataset.choice = '';\n            div.dataset.id = choice.id;\n            div.dataset.value = rawValue;\n            if (selectText) {\n                div.dataset.selectText = selectText;\n            }\n            if (choice.group) {\n                div.dataset.groupId = \"\".concat(choice.group.id);\n            }\n            assignCustomProperties(div, choice, false);\n            if (choice.disabled) {\n                addClassesToElement(div, itemDisabled);\n                div.dataset.choiceDisabled = '';\n                div.setAttribute('aria-disabled', 'true');\n            }\n            else {\n                addClassesToElement(div, itemSelectable);\n                div.dataset.choiceSelectable = '';\n                div.setAttribute('aria-selected', choice.selected ? 'true' : 'false');\n            }\n            return div;\n        },\n        input: function (_a, placeholderValue) {\n            var _b = _a.classNames, input = _b.input, inputCloned = _b.inputCloned, labelId = _a.labelId;\n            var inp = document.createElement('input');\n            inp.type = 'search';\n            addClassesToElement(inp, input);\n            addClassesToElement(inp, inputCloned);\n            inp.autocomplete = 'off';\n            inp.autocapitalize = 'off';\n            inp.spellcheck = false;\n            inp.setAttribute('aria-autocomplete', 'list');\n            if (placeholderValue) {\n                inp.setAttribute('aria-label', placeholderValue);\n            }\n            else if (!labelId) {\n                addAriaLabel(this._docRoot, this.passedElement.element.id, inp);\n            }\n            return inp;\n        },\n        dropdown: function (_a) {\n            var _b = _a.classNames, list = _b.list, listDropdown = _b.listDropdown;\n            var div = document.createElement('div');\n            addClassesToElement(div, list);\n            addClassesToElement(div, listDropdown);\n            div.setAttribute('aria-expanded', 'false');\n            return div;\n        },\n        notice: function (_a, innerHTML, type) {\n            var _b = _a.classNames, item = _b.item, itemChoice = _b.itemChoice, addChoice = _b.addChoice, noResults = _b.noResults, noChoices = _b.noChoices, noticeItem = _b.notice;\n            if (type === void 0) { type = NoticeTypes.generic; }\n            var notice = document.createElement('div');\n            setElementHtml(notice, true, innerHTML);\n            addClassesToElement(notice, item);\n            addClassesToElement(notice, itemChoice);\n            addClassesToElement(notice, noticeItem);\n            // eslint-disable-next-line default-case\n            switch (type) {\n                case NoticeTypes.addChoice:\n                    addClassesToElement(notice, addChoice);\n                    break;\n                case NoticeTypes.noResults:\n                    addClassesToElement(notice, noResults);\n                    break;\n                case NoticeTypes.noChoices:\n                    addClassesToElement(notice, noChoices);\n                    break;\n            }\n            if (type === NoticeTypes.addChoice) {\n                notice.dataset.choiceSelectable = '';\n                notice.dataset.choice = '';\n            }\n            return notice;\n        },\n        option: function (choice) {\n            // HtmlOptionElement's label value does not support HTML, so the avoid double escaping unwrap the untrusted string.\n            var labelValue = unwrapStringForRaw(choice.label);\n            var opt = new Option(labelValue, choice.value, false, choice.selected);\n            assignCustomProperties(opt, choice, true);\n            opt.disabled = choice.disabled;\n            if (choice.selected) {\n                opt.setAttribute('selected', '');\n            }\n            return opt;\n        },\n    };\n\n    /** @see {@link http://browserhacks.com/#hack-acea075d0ac6954f275a70023906050c} */\n    var IS_IE11 = '-ms-scroll-limit' in document.documentElement.style &&\n        '-ms-ime-align' in document.documentElement.style;\n    var USER_DEFAULTS = {};\n    var parseDataSetId = function (element) {\n        if (!element) {\n            return undefined;\n        }\n        return element.dataset.id ? parseInt(element.dataset.id, 10) : undefined;\n    };\n    var selectableChoiceIdentifier = '[data-choice-selectable]';\n    /**\n     * Choices\n     * @author Josh Johnson<josh@joshuajohnson.co.uk>\n     */\n    var Choices = /** @class */ (function () {\n        function Choices(element, userConfig) {\n            if (element === void 0) { element = '[data-choice]'; }\n            if (userConfig === void 0) { userConfig = {}; }\n            var _this = this;\n            this.initialisedOK = undefined;\n            this._hasNonChoicePlaceholder = false;\n            this._lastAddedChoiceId = 0;\n            this._lastAddedGroupId = 0;\n            var defaults = Choices.defaults;\n            this.config = __assign(__assign(__assign({}, defaults.allOptions), defaults.options), userConfig);\n            ObjectsInConfig.forEach(function (key) {\n                _this.config[key] = __assign(__assign(__assign({}, defaults.allOptions[key]), defaults.options[key]), userConfig[key]);\n            });\n            var config = this.config;\n            if (!config.silent) {\n                this._validateConfig();\n            }\n            var docRoot = config.shadowRoot || document.documentElement;\n            this._docRoot = docRoot;\n            var passedElement = typeof element === 'string' ? docRoot.querySelector(element) : element;\n            if (!passedElement ||\n                typeof passedElement !== 'object' ||\n                !(isHtmlInputElement(passedElement) || isHtmlSelectElement(passedElement))) {\n                if (!passedElement && typeof element === 'string') {\n                    throw TypeError(\"Selector \".concat(element, \" failed to find an element\"));\n                }\n                throw TypeError(\"Expected one of the following types text|select-one|select-multiple\");\n            }\n            var elementType = passedElement.type;\n            var isText = elementType === PassedElementTypes.Text;\n            if (isText || config.maxItemCount !== 1) {\n                config.singleModeForMultiSelect = false;\n            }\n            if (config.singleModeForMultiSelect) {\n                elementType = PassedElementTypes.SelectMultiple;\n            }\n            var isSelectOne = elementType === PassedElementTypes.SelectOne;\n            var isSelectMultiple = elementType === PassedElementTypes.SelectMultiple;\n            var isSelect = isSelectOne || isSelectMultiple;\n            this._elementType = elementType;\n            this._isTextElement = isText;\n            this._isSelectOneElement = isSelectOne;\n            this._isSelectMultipleElement = isSelectMultiple;\n            this._isSelectElement = isSelectOne || isSelectMultiple;\n            this._canAddUserChoices = (isText && config.addItems) || (isSelect && config.addChoices);\n            if (typeof config.renderSelectedChoices !== 'boolean') {\n                config.renderSelectedChoices = config.renderSelectedChoices === 'always' || isSelectOne;\n            }\n            if (config.closeDropdownOnSelect === 'auto') {\n                config.closeDropdownOnSelect = isText || isSelectOne || config.singleModeForMultiSelect;\n            }\n            else {\n                config.closeDropdownOnSelect = coerceBool(config.closeDropdownOnSelect);\n            }\n            if (config.placeholder) {\n                if (config.placeholderValue) {\n                    this._hasNonChoicePlaceholder = true;\n                }\n                else if (passedElement.dataset.placeholder) {\n                    this._hasNonChoicePlaceholder = true;\n                    config.placeholderValue = passedElement.dataset.placeholder;\n                }\n            }\n            if (userConfig.addItemFilter && typeof userConfig.addItemFilter !== 'function') {\n                var re = userConfig.addItemFilter instanceof RegExp ? userConfig.addItemFilter : new RegExp(userConfig.addItemFilter);\n                config.addItemFilter = re.test.bind(re);\n            }\n            if (this._isTextElement) {\n                this.passedElement = new WrappedInput({\n                    element: passedElement,\n                    classNames: config.classNames,\n                });\n            }\n            else {\n                var selectEl = passedElement;\n                this.passedElement = new WrappedSelect({\n                    element: selectEl,\n                    classNames: config.classNames,\n                    template: function (data) { return _this._templates.option(data); },\n                    extractPlaceholder: config.placeholder && !this._hasNonChoicePlaceholder,\n                });\n            }\n            this.initialised = false;\n            this._store = new Store(config);\n            this._currentValue = '';\n            config.searchEnabled = !isText && config.searchEnabled;\n            this._canSearch = config.searchEnabled;\n            this._isScrollingOnIe = false;\n            this._highlightPosition = 0;\n            this._wasTap = true;\n            this._placeholderValue = this._generatePlaceholderValue();\n            this._baseId = generateId(passedElement, 'choices-');\n            /**\n             * setting direction in cases where it's explicitly set on passedElement\n             * or when calculated direction is different from the document\n             */\n            this._direction = passedElement.dir;\n            if (!this._direction) {\n                var elementDirection = window.getComputedStyle(passedElement).direction;\n                var documentDirection = window.getComputedStyle(document.documentElement).direction;\n                if (elementDirection !== documentDirection) {\n                    this._direction = elementDirection;\n                }\n            }\n            this._idNames = {\n                itemChoice: 'item-choice',\n            };\n            this._templates = defaults.templates;\n            this._render = this._render.bind(this);\n            this._onFocus = this._onFocus.bind(this);\n            this._onBlur = this._onBlur.bind(this);\n            this._onKeyUp = this._onKeyUp.bind(this);\n            this._onKeyDown = this._onKeyDown.bind(this);\n            this._onInput = this._onInput.bind(this);\n            this._onClick = this._onClick.bind(this);\n            this._onTouchMove = this._onTouchMove.bind(this);\n            this._onTouchEnd = this._onTouchEnd.bind(this);\n            this._onMouseDown = this._onMouseDown.bind(this);\n            this._onMouseOver = this._onMouseOver.bind(this);\n            this._onFormReset = this._onFormReset.bind(this);\n            this._onSelectKey = this._onSelectKey.bind(this);\n            this._onEnterKey = this._onEnterKey.bind(this);\n            this._onEscapeKey = this._onEscapeKey.bind(this);\n            this._onDirectionKey = this._onDirectionKey.bind(this);\n            this._onDeleteKey = this._onDeleteKey.bind(this);\n            this._onChange = this._onChange.bind(this);\n            this._onInvalid = this._onInvalid.bind(this);\n            // If element has already been initialised with Choices, fail silently\n            if (this.passedElement.isActive) {\n                if (!config.silent) {\n                    console.warn('Trying to initialise Choices on element already initialised', { element: element });\n                }\n                this.initialised = true;\n                this.initialisedOK = false;\n                return;\n            }\n            // Let's go\n            this.init();\n            // preserve the selected item list after setup for form reset\n            this._initialItems = this._store.items.map(function (choice) { return choice.value; });\n        }\n        Object.defineProperty(Choices, \"defaults\", {\n            get: function () {\n                return Object.preventExtensions({\n                    get options() {\n                        return USER_DEFAULTS;\n                    },\n                    get allOptions() {\n                        return DEFAULT_CONFIG;\n                    },\n                    get templates() {\n                        return templates;\n                    },\n                });\n            },\n            enumerable: false,\n            configurable: true\n        });\n        Choices.prototype.init = function () {\n            if (this.initialised || this.initialisedOK !== undefined) {\n                return;\n            }\n            this._searcher = getSearcher(this.config);\n            this._loadChoices();\n            this._createTemplates();\n            this._createElements();\n            this._createStructure();\n            if ((this._isTextElement && !this.config.addItems) ||\n                this.passedElement.element.hasAttribute('disabled') ||\n                !!this.passedElement.element.closest('fieldset:disabled')) {\n                this.disable();\n            }\n            else {\n                this.enable();\n                this._addEventListeners();\n            }\n            // should be triggered **after** disabled state to avoid additional re-draws\n            this._initStore();\n            this.initialised = true;\n            this.initialisedOK = true;\n            var callbackOnInit = this.config.callbackOnInit;\n            // Run callback if it is a function\n            if (typeof callbackOnInit === 'function') {\n                callbackOnInit.call(this);\n            }\n        };\n        Choices.prototype.destroy = function () {\n            if (!this.initialised) {\n                return;\n            }\n            this._removeEventListeners();\n            this.passedElement.reveal();\n            this.containerOuter.unwrap(this.passedElement.element);\n            this._store._listeners = []; // prevents select/input value being wiped\n            this.clearStore(false);\n            this._stopSearch();\n            this._templates = Choices.defaults.templates;\n            this.initialised = false;\n            this.initialisedOK = undefined;\n        };\n        Choices.prototype.enable = function () {\n            if (this.passedElement.isDisabled) {\n                this.passedElement.enable();\n            }\n            if (this.containerOuter.isDisabled) {\n                this._addEventListeners();\n                this.input.enable();\n                this.containerOuter.enable();\n            }\n            return this;\n        };\n        Choices.prototype.disable = function () {\n            if (!this.passedElement.isDisabled) {\n                this.passedElement.disable();\n            }\n            if (!this.containerOuter.isDisabled) {\n                this._removeEventListeners();\n                this.input.disable();\n                this.containerOuter.disable();\n            }\n            return this;\n        };\n        Choices.prototype.highlightItem = function (item, runEvent) {\n            if (runEvent === void 0) { runEvent = true; }\n            if (!item || !item.id) {\n                return this;\n            }\n            var choice = this._store.items.find(function (c) { return c.id === item.id; });\n            if (!choice || choice.highlighted) {\n                return this;\n            }\n            this._store.dispatch(highlightItem(choice, true));\n            if (runEvent) {\n                this.passedElement.triggerEvent(EventType.highlightItem, getChoiceForOutput(choice));\n            }\n            return this;\n        };\n        Choices.prototype.unhighlightItem = function (item, runEvent) {\n            if (runEvent === void 0) { runEvent = true; }\n            if (!item || !item.id) {\n                return this;\n            }\n            var choice = this._store.items.find(function (c) { return c.id === item.id; });\n            if (!choice || !choice.highlighted) {\n                return this;\n            }\n            this._store.dispatch(highlightItem(choice, false));\n            if (runEvent) {\n                this.passedElement.triggerEvent(EventType.unhighlightItem, getChoiceForOutput(choice));\n            }\n            return this;\n        };\n        Choices.prototype.highlightAll = function () {\n            var _this = this;\n            this._store.withTxn(function () {\n                _this._store.items.forEach(function (item) {\n                    if (!item.highlighted) {\n                        _this._store.dispatch(highlightItem(item, true));\n                        _this.passedElement.triggerEvent(EventType.highlightItem, getChoiceForOutput(item));\n                    }\n                });\n            });\n            return this;\n        };\n        Choices.prototype.unhighlightAll = function () {\n            var _this = this;\n            this._store.withTxn(function () {\n                _this._store.items.forEach(function (item) {\n                    if (item.highlighted) {\n                        _this._store.dispatch(highlightItem(item, false));\n                        _this.passedElement.triggerEvent(EventType.highlightItem, getChoiceForOutput(item));\n                    }\n                });\n            });\n            return this;\n        };\n        Choices.prototype.removeActiveItemsByValue = function (value) {\n            var _this = this;\n            this._store.withTxn(function () {\n                _this._store.items.filter(function (item) { return item.value === value; }).forEach(function (item) { return _this._removeItem(item); });\n            });\n            return this;\n        };\n        Choices.prototype.removeActiveItems = function (excludedId) {\n            var _this = this;\n            this._store.withTxn(function () {\n                _this._store.items.filter(function (_a) {\n                    var id = _a.id;\n                    return id !== excludedId;\n                }).forEach(function (item) { return _this._removeItem(item); });\n            });\n            return this;\n        };\n        Choices.prototype.removeHighlightedItems = function (runEvent) {\n            var _this = this;\n            if (runEvent === void 0) { runEvent = false; }\n            this._store.withTxn(function () {\n                _this._store.highlightedActiveItems.forEach(function (item) {\n                    _this._removeItem(item);\n                    // If this action was performed by the user\n                    // trigger the event\n                    if (runEvent) {\n                        _this._triggerChange(item.value);\n                    }\n                });\n            });\n            return this;\n        };\n        Choices.prototype.showDropdown = function (preventInputFocus) {\n            var _this = this;\n            if (this.dropdown.isActive) {\n                return this;\n            }\n            if (preventInputFocus === undefined) {\n                // eslint-disable-next-line no-param-reassign\n                preventInputFocus = !this._canSearch;\n            }\n            requestAnimationFrame(function () {\n                _this.dropdown.show();\n                var rect = _this.dropdown.element.getBoundingClientRect();\n                _this.containerOuter.open(rect.bottom, rect.height);\n                if (!preventInputFocus) {\n                    _this.input.focus();\n                }\n                _this.passedElement.triggerEvent(EventType.showDropdown);\n                var activeElement = _this.choiceList.element.querySelector(getClassNamesSelector(_this.config.classNames.selectedState));\n                if (activeElement !== null && !isScrolledIntoView(activeElement, _this.choiceList.element)) {\n                    // We use the native scrollIntoView function instead of choiceList.scrollToChildElement to avoid animated scroll.\n                    activeElement.scrollIntoView();\n                }\n            });\n            return this;\n        };\n        Choices.prototype.hideDropdown = function (preventInputBlur) {\n            var _this = this;\n            if (!this.dropdown.isActive) {\n                return this;\n            }\n            this._removeHighlightedChoices();\n            requestAnimationFrame(function () {\n                _this.dropdown.hide();\n                _this.containerOuter.close();\n                if (!preventInputBlur && _this._canSearch) {\n                    _this.input.removeActiveDescendant();\n                    _this.input.blur();\n                }\n                _this.passedElement.triggerEvent(EventType.hideDropdown);\n            });\n            return this;\n        };\n        Choices.prototype.getValue = function (valueOnly) {\n            var values = this._store.items.map(function (item) {\n                return (valueOnly ? item.value : getChoiceForOutput(item));\n            });\n            return this._isSelectOneElement || this.config.singleModeForMultiSelect ? values[0] : values;\n        };\n        Choices.prototype.setValue = function (items) {\n            var _this = this;\n            if (!this.initialisedOK) {\n                this._warnChoicesInitFailed('setValue');\n                return this;\n            }\n            this._store.withTxn(function () {\n                items.forEach(function (value) {\n                    if (value) {\n                        _this._addChoice(mapInputToChoice(value, false));\n                    }\n                });\n            });\n            // @todo integrate with Store\n            this._searcher.reset();\n            return this;\n        };\n        Choices.prototype.setChoiceByValue = function (value) {\n            var _this = this;\n            if (!this.initialisedOK) {\n                this._warnChoicesInitFailed('setChoiceByValue');\n                return this;\n            }\n            if (this._isTextElement) {\n                return this;\n            }\n            this._store.withTxn(function () {\n                // If only one value has been passed, convert to array\n                var choiceValue = Array.isArray(value) ? value : [value];\n                // Loop through each value and\n                choiceValue.forEach(function (val) { return _this._findAndSelectChoiceByValue(val); });\n                _this.unhighlightAll();\n            });\n            // @todo integrate with Store\n            this._searcher.reset();\n            return this;\n        };\n        /**\n         * Set choices of select input via an array of objects (or function that returns array of object or promise of it),\n         * a value field name and a label field name.\n         * This behaves the same as passing items via the choices option but can be called after initialising Choices.\n         * This can also be used to add groups of choices (see example 2); Optionally pass a true `replaceChoices` value to remove any existing choices.\n         * Optionally pass a `customProperties` object to add additional data to your choices (useful when searching/filtering etc).\n         *\n         * **Input types affected:** select-one, select-multiple\n         *\n         * @example\n         * ```js\n         * const example = new Choices(element);\n         *\n         * example.setChoices([\n         *   {value: 'One', label: 'Label One', disabled: true},\n         *   {value: 'Two', label: 'Label Two', selected: true},\n         *   {value: 'Three', label: 'Label Three'},\n         * ], 'value', 'label', false);\n         * ```\n         *\n         * @example\n         * ```js\n         * const example = new Choices(element);\n         *\n         * example.setChoices(async () => {\n         *   try {\n         *      const items = await fetch('/items');\n         *      return items.json()\n         *   } catch(err) {\n         *      console.error(err)\n         *   }\n         * });\n         * ```\n         *\n         * @example\n         * ```js\n         * const example = new Choices(element);\n         *\n         * example.setChoices([{\n         *   label: 'Group one',\n         *   id: 1,\n         *   disabled: false,\n         *   choices: [\n         *     {value: 'Child One', label: 'Child One', selected: true},\n         *     {value: 'Child Two', label: 'Child Two',  disabled: true},\n         *     {value: 'Child Three', label: 'Child Three'},\n         *   ]\n         * },\n         * {\n         *   label: 'Group two',\n         *   id: 2,\n         *   disabled: false,\n         *   choices: [\n         *     {value: 'Child Four', label: 'Child Four', disabled: true},\n         *     {value: 'Child Five', label: 'Child Five'},\n         *     {value: 'Child Six', label: 'Child Six', customProperties: {\n         *       description: 'Custom description about child six',\n         *       random: 'Another random custom property'\n         *     }},\n         *   ]\n         * }], 'value', 'label', false);\n         * ```\n         */\n        Choices.prototype.setChoices = function (choicesArrayOrFetcher, value, label, replaceChoices, clearSearchFlag, replaceItems) {\n            var _this = this;\n            if (choicesArrayOrFetcher === void 0) { choicesArrayOrFetcher = []; }\n            if (value === void 0) { value = 'value'; }\n            if (label === void 0) { label = 'label'; }\n            if (replaceChoices === void 0) { replaceChoices = false; }\n            if (clearSearchFlag === void 0) { clearSearchFlag = true; }\n            if (replaceItems === void 0) { replaceItems = false; }\n            if (!this.initialisedOK) {\n                this._warnChoicesInitFailed('setChoices');\n                return this;\n            }\n            if (!this._isSelectElement) {\n                throw new TypeError(\"setChoices can't be used with INPUT based Choices\");\n            }\n            if (typeof value !== 'string' || !value) {\n                throw new TypeError(\"value parameter must be a name of 'value' field in passed objects\");\n            }\n            if (typeof choicesArrayOrFetcher === 'function') {\n                // it's a choices fetcher function\n                var fetcher_1 = choicesArrayOrFetcher(this);\n                if (typeof Promise === 'function' && fetcher_1 instanceof Promise) {\n                    // that's a promise\n                    // eslint-disable-next-line no-promise-executor-return\n                    return new Promise(function (resolve) { return requestAnimationFrame(resolve); })\n                        .then(function () { return _this._handleLoadingState(true); })\n                        .then(function () { return fetcher_1; })\n                        .then(function (data) {\n                        return _this.setChoices(data, value, label, replaceChoices, clearSearchFlag, replaceItems);\n                    })\n                        .catch(function (err) {\n                        if (!_this.config.silent) {\n                            console.error(err);\n                        }\n                    })\n                        .then(function () { return _this._handleLoadingState(false); })\n                        .then(function () { return _this; });\n                }\n                // function returned something else than promise, let's check if it's an array of choices\n                if (!Array.isArray(fetcher_1)) {\n                    throw new TypeError(\".setChoices first argument function must return either array of choices or Promise, got: \".concat(typeof fetcher_1));\n                }\n                // recursion with results, it's sync and choices were cleared already\n                return this.setChoices(fetcher_1, value, label, false);\n            }\n            if (!Array.isArray(choicesArrayOrFetcher)) {\n                throw new TypeError(\".setChoices must be called either with array of choices with a function resulting into Promise of array of choices\");\n            }\n            this.containerOuter.removeLoadingState();\n            this._store.withTxn(function () {\n                if (clearSearchFlag) {\n                    _this._isSearching = false;\n                }\n                // Clear choices if needed\n                if (replaceChoices) {\n                    _this.clearChoices(true, replaceItems);\n                }\n                var isDefaultValue = value === 'value';\n                var isDefaultLabel = label === 'label';\n                choicesArrayOrFetcher.forEach(function (groupOrChoice) {\n                    if ('choices' in groupOrChoice) {\n                        var group = groupOrChoice;\n                        if (!isDefaultLabel) {\n                            group = __assign(__assign({}, group), { label: group[label] });\n                        }\n                        _this._addGroup(mapInputToChoice(group, true));\n                    }\n                    else {\n                        var choice = groupOrChoice;\n                        if (!isDefaultLabel || !isDefaultValue) {\n                            choice = __assign(__assign({}, choice), { value: choice[value], label: choice[label] });\n                        }\n                        var choiceFull = mapInputToChoice(choice, false);\n                        _this._addChoice(choiceFull);\n                        if (choiceFull.placeholder && !_this._hasNonChoicePlaceholder) {\n                            _this._placeholderValue = unwrapStringForEscaped(choiceFull.label);\n                        }\n                    }\n                });\n                _this.unhighlightAll();\n            });\n            // @todo integrate with Store\n            this._searcher.reset();\n            return this;\n        };\n        Choices.prototype.refresh = function (withEvents, selectFirstOption, deselectAll) {\n            var _this = this;\n            if (withEvents === void 0) { withEvents = false; }\n            if (selectFirstOption === void 0) { selectFirstOption = false; }\n            if (deselectAll === void 0) { deselectAll = false; }\n            if (!this._isSelectElement) {\n                if (!this.config.silent) {\n                    console.warn('refresh method can only be used on choices backed by a <select> element');\n                }\n                return this;\n            }\n            this._store.withTxn(function () {\n                var choicesFromOptions = _this.passedElement.optionsAsChoices();\n                // Build the list of items which require preserving\n                var existingItems = {};\n                if (!deselectAll) {\n                    _this._store.items.forEach(function (choice) {\n                        if (choice.id && choice.active && choice.selected) {\n                            existingItems[choice.value] = true;\n                        }\n                    });\n                }\n                _this.clearStore(false);\n                var updateChoice = function (choice) {\n                    if (deselectAll) {\n                        _this._store.dispatch(removeItem$1(choice));\n                    }\n                    else if (existingItems[choice.value]) {\n                        choice.selected = true;\n                    }\n                };\n                choicesFromOptions.forEach(function (groupOrChoice) {\n                    if ('choices' in groupOrChoice) {\n                        groupOrChoice.choices.forEach(updateChoice);\n                        return;\n                    }\n                    updateChoice(groupOrChoice);\n                });\n                /* @todo only generate add events for the added options instead of all\n                if (withEvents) {\n                  items.forEach((choice) => {\n                    if (existingItems[choice.value]) {\n                      this.passedElement.triggerEvent(\n                        EventType.removeItem,\n                        this._getChoiceForEvent(choice),\n                      );\n                    }\n                  });\n                }\n                */\n                // load new choices & items\n                _this._addPredefinedChoices(choicesFromOptions, selectFirstOption, withEvents);\n                // re-do search if required\n                if (_this._isSearching) {\n                    _this._searchChoices(_this.input.value);\n                }\n            });\n            return this;\n        };\n        Choices.prototype.removeChoice = function (value) {\n            var choice = this._store.choices.find(function (c) { return c.value === value; });\n            if (!choice) {\n                return this;\n            }\n            this._clearNotice();\n            this._store.dispatch(removeChoice(choice));\n            // @todo integrate with Store\n            this._searcher.reset();\n            if (choice.selected) {\n                this.passedElement.triggerEvent(EventType.removeItem, getChoiceForOutput(choice));\n            }\n            return this;\n        };\n        Choices.prototype.clearChoices = function (clearOptions, clearItems) {\n            var _this = this;\n            if (clearOptions === void 0) { clearOptions = true; }\n            if (clearItems === void 0) { clearItems = false; }\n            if (clearOptions) {\n                if (clearItems) {\n                    this.passedElement.element.replaceChildren('');\n                }\n                else {\n                    this.passedElement.element.querySelectorAll(':not([selected])').forEach(function (el) {\n                        el.remove();\n                    });\n                }\n            }\n            this.itemList.element.replaceChildren('');\n            this.choiceList.element.replaceChildren('');\n            this._clearNotice();\n            this._store.withTxn(function () {\n                var items = clearItems ? [] : _this._store.items;\n                _this._store.reset();\n                items.forEach(function (item) {\n                    _this._store.dispatch(addChoice(item));\n                    _this._store.dispatch(addItem(item));\n                });\n            });\n            // @todo integrate with Store\n            this._searcher.reset();\n            return this;\n        };\n        Choices.prototype.clearStore = function (clearOptions) {\n            if (clearOptions === void 0) { clearOptions = true; }\n            this.clearChoices(clearOptions, true);\n            this._stopSearch();\n            this._lastAddedChoiceId = 0;\n            this._lastAddedGroupId = 0;\n            return this;\n        };\n        Choices.prototype.clearInput = function () {\n            var shouldSetInputWidth = !this._isSelectOneElement;\n            this.input.clear(shouldSetInputWidth);\n            this._stopSearch();\n            return this;\n        };\n        Choices.prototype._validateConfig = function () {\n            var config = this.config;\n            var invalidConfigOptions = diff(config, DEFAULT_CONFIG);\n            if (invalidConfigOptions.length) {\n                console.warn('Unknown config option(s) passed', invalidConfigOptions.join(', '));\n            }\n            if (config.allowHTML && config.allowHtmlUserInput) {\n                if (config.addItems) {\n                    console.warn('Warning: allowHTML/allowHtmlUserInput/addItems all being true is strongly not recommended and may lead to XSS attacks');\n                }\n                if (config.addChoices) {\n                    console.warn('Warning: allowHTML/allowHtmlUserInput/addChoices all being true is strongly not recommended and may lead to XSS attacks');\n                }\n            }\n        };\n        Choices.prototype._render = function (changes) {\n            if (changes === void 0) { changes = { choices: true, groups: true, items: true }; }\n            if (this._store.inTxn()) {\n                return;\n            }\n            if (this._isSelectElement) {\n                if (changes.choices || changes.groups) {\n                    this._renderChoices();\n                }\n            }\n            if (changes.items) {\n                this._renderItems();\n            }\n        };\n        Choices.prototype._renderChoices = function () {\n            var _this = this;\n            if (!this._canAddItems()) {\n                return; // block rendering choices if the input limit is reached.\n            }\n            var _a = this, config = _a.config, isSearching = _a._isSearching;\n            var _b = this._store, activeGroups = _b.activeGroups, activeChoices = _b.activeChoices;\n            var renderLimit = isSearching ? config.searchResultLimit : config.renderChoiceLimit;\n            if (this._isSelectElement) {\n                var backingOptions = activeChoices.filter(function (choice) { return !choice.element; });\n                if (backingOptions.length) {\n                    this.passedElement.addOptions(backingOptions);\n                }\n            }\n            var fragment = document.createDocumentFragment();\n            var renderableChoices = function (choices) {\n                return choices.filter(function (choice) {\n                    return !choice.placeholder &&\n                        (isSearching\n                            ? (config.searchRenderSelectedChoices || !choice.selected) && !!choice.rank\n                            : config.renderSelectedChoices || !choice.selected);\n                });\n            };\n            var showLabel = config.appendGroupInSearch && isSearching;\n            var selectableChoices = false;\n            var highlightedEl = null;\n            var renderChoices = function (choices, withinGroup) {\n                if (isSearching) {\n                    // sortByRank is used to ensure stable sorting, as scores are non-unique\n                    // this additionally ensures fuseOptions.sortFn is not ignored\n                    choices.sort(sortByRank);\n                }\n                else if (config.shouldSort) {\n                    choices.sort(config.sorter);\n                }\n                var choiceLimit = choices.length;\n                choiceLimit = !withinGroup && renderLimit > 0 && choiceLimit > renderLimit ? renderLimit : choiceLimit;\n                choiceLimit--;\n                choices.every(function (choice, index) {\n                    // choiceEl being empty signals the contents has probably significantly changed\n                    var dropdownItem = choice.choiceEl ||\n                        _this._templates.choice(config, choice, config.itemSelectText, showLabel && choice.group ? choice.group.label : undefined);\n                    choice.choiceEl = dropdownItem;\n                    fragment.appendChild(dropdownItem);\n                    if (isSearching || !choice.selected) {\n                        selectableChoices = true;\n                    }\n                    else if (!highlightedEl) {\n                        highlightedEl = dropdownItem;\n                    }\n                    return index < choiceLimit;\n                });\n            };\n            if (activeChoices.length) {\n                if (config.resetScrollPosition) {\n                    requestAnimationFrame(function () { return _this.choiceList.scrollToTop(); });\n                }\n                if (!this._hasNonChoicePlaceholder && !isSearching && this._isSelectOneElement) {\n                    // If we have a placeholder choice along with groups\n                    renderChoices(activeChoices.filter(function (choice) { return choice.placeholder && !choice.group; }), false);\n                }\n                // If we have grouped options\n                if (activeGroups.length && !isSearching) {\n                    if (config.shouldSort) {\n                        activeGroups.sort(config.sorter);\n                    }\n                    // render Choices without group first, regardless of sort, otherwise they won't be distinguishable\n                    // from the last group\n                    renderChoices(activeChoices.filter(function (choice) { return !choice.placeholder && !choice.group; }), false);\n                    activeGroups.forEach(function (group) {\n                        var groupChoices = renderableChoices(group.choices);\n                        if (groupChoices.length) {\n                            if (group.label) {\n                                var dropdownGroup = group.groupEl || _this._templates.choiceGroup(_this.config, group);\n                                group.groupEl = dropdownGroup;\n                                dropdownGroup.remove();\n                                fragment.appendChild(dropdownGroup);\n                            }\n                            renderChoices(groupChoices, true);\n                        }\n                    });\n                }\n                else {\n                    renderChoices(renderableChoices(activeChoices), false);\n                }\n            }\n            if (!selectableChoices && (isSearching || !fragment.children.length || !config.renderSelectedChoices)) {\n                if (!this._notice) {\n                    this._notice = {\n                        text: resolveStringFunction(isSearching ? config.noResultsText : config.noChoicesText),\n                        type: isSearching ? NoticeTypes.noResults : NoticeTypes.noChoices,\n                    };\n                }\n                fragment.replaceChildren('');\n            }\n            this._renderNotice(fragment);\n            this.choiceList.element.replaceChildren(fragment);\n            this._highlightChoice(highlightedEl);\n        };\n        Choices.prototype._renderItems = function () {\n            var _this = this;\n            var items = this._store.items || [];\n            var itemList = this.itemList.element;\n            var config = this.config;\n            var fragment = document.createDocumentFragment();\n            var itemFromList = function (item) {\n                return itemList.querySelector(\"[data-item][data-id=\\\"\".concat(item.id, \"\\\"]\"));\n            };\n            var addItemToFragment = function (item) {\n                var el = item.itemEl;\n                if (el && el.parentElement) {\n                    return;\n                }\n                el = itemFromList(item) || _this._templates.item(config, item, config.removeItemButton);\n                item.itemEl = el;\n                fragment.appendChild(el);\n            };\n            // new items\n            items.forEach(addItemToFragment);\n            var addedItems = !!fragment.childNodes.length;\n            if (this._isSelectOneElement) {\n                var existingItems = itemList.children.length;\n                if (addedItems || existingItems > 1) {\n                    var placeholder = itemList.querySelector(getClassNamesSelector(config.classNames.placeholder));\n                    if (placeholder) {\n                        placeholder.remove();\n                    }\n                }\n                else if (!addedItems && !existingItems && this._placeholderValue) {\n                    addedItems = true;\n                    addItemToFragment(mapInputToChoice({\n                        selected: true,\n                        value: '',\n                        label: this._placeholderValue,\n                        placeholder: true,\n                    }, false));\n                }\n            }\n            if (addedItems) {\n                itemList.append(fragment);\n                if (config.shouldSortItems && !this._isSelectOneElement) {\n                    items.sort(config.sorter);\n                    // push sorting into the DOM\n                    items.forEach(function (item) {\n                        var el = itemFromList(item);\n                        if (el) {\n                            el.remove();\n                            fragment.append(el);\n                        }\n                    });\n                    itemList.append(fragment);\n                }\n            }\n            if (this._isTextElement) {\n                // Update the value of the hidden input\n                this.passedElement.value = items.map(function (_a) {\n                    var value = _a.value;\n                    return value;\n                }).join(config.delimiter);\n            }\n        };\n        Choices.prototype._displayNotice = function (text, type, openDropdown) {\n            if (openDropdown === void 0) { openDropdown = true; }\n            var oldNotice = this._notice;\n            if (oldNotice &&\n                ((oldNotice.type === type && oldNotice.text === text) ||\n                    (oldNotice.type === NoticeTypes.addChoice &&\n                        (type === NoticeTypes.noResults || type === NoticeTypes.noChoices)))) {\n                if (openDropdown) {\n                    this.showDropdown(true);\n                }\n                return;\n            }\n            this._clearNotice();\n            this._notice = text\n                ? {\n                    text: text,\n                    type: type,\n                }\n                : undefined;\n            this._renderNotice();\n            if (openDropdown && text) {\n                this.showDropdown(true);\n            }\n        };\n        Choices.prototype._clearNotice = function () {\n            if (!this._notice) {\n                return;\n            }\n            var noticeElement = this.choiceList.element.querySelector(getClassNamesSelector(this.config.classNames.notice));\n            if (noticeElement) {\n                noticeElement.remove();\n            }\n            this._notice = undefined;\n        };\n        Choices.prototype._renderNotice = function (fragment) {\n            var noticeConf = this._notice;\n            if (noticeConf) {\n                var notice = this._templates.notice(this.config, noticeConf.text, noticeConf.type);\n                if (fragment) {\n                    fragment.append(notice);\n                }\n                else {\n                    this.choiceList.prepend(notice);\n                }\n            }\n        };\n        /**\n         * @deprecated Use utils.getChoiceForOutput\n         */\n        // eslint-disable-next-line class-methods-use-this\n        Choices.prototype._getChoiceForOutput = function (choice, keyCode) {\n            return getChoiceForOutput(choice, keyCode);\n        };\n        Choices.prototype._triggerChange = function (value) {\n            if (value === undefined || value === null) {\n                return;\n            }\n            this.passedElement.triggerEvent(EventType.change, {\n                value: value,\n            });\n        };\n        Choices.prototype._handleButtonAction = function (element) {\n            var _this = this;\n            var items = this._store.items;\n            if (!items.length || !this.config.removeItems || !this.config.removeItemButton) {\n                return;\n            }\n            var id = element && parseDataSetId(element.closest('[data-id]'));\n            var itemToRemove = id && items.find(function (item) { return item.id === id; });\n            if (!itemToRemove) {\n                return;\n            }\n            this._store.withTxn(function () {\n                // Remove item associated with button\n                _this._removeItem(itemToRemove);\n                _this._triggerChange(itemToRemove.value);\n                if (_this._isSelectOneElement && !_this._hasNonChoicePlaceholder) {\n                    var placeholderChoice = (_this.config.shouldSort ? _this._store.choices.reverse() : _this._store.choices).find(function (choice) { return choice.placeholder; });\n                    if (placeholderChoice) {\n                        _this._addItem(placeholderChoice);\n                        _this.unhighlightAll();\n                        if (placeholderChoice.value) {\n                            _this._triggerChange(placeholderChoice.value);\n                        }\n                    }\n                }\n            });\n        };\n        Choices.prototype._handleItemAction = function (element, hasShiftKey) {\n            var _this = this;\n            if (hasShiftKey === void 0) { hasShiftKey = false; }\n            var items = this._store.items;\n            if (!items.length || !this.config.removeItems || this._isSelectOneElement) {\n                return;\n            }\n            var id = parseDataSetId(element);\n            if (!id) {\n                return;\n            }\n            // We only want to select one item with a click\n            // so we deselect any items that aren't the target\n            // unless shift is being pressed\n            items.forEach(function (item) {\n                if (item.id === id && !item.highlighted) {\n                    _this.highlightItem(item);\n                }\n                else if (!hasShiftKey && item.highlighted) {\n                    _this.unhighlightItem(item);\n                }\n            });\n            // Focus input as without focus, a user cannot do anything with a\n            // highlighted item\n            this.input.focus();\n        };\n        Choices.prototype._handleChoiceAction = function (element) {\n            var _this = this;\n            // If we are clicking on an option\n            var id = parseDataSetId(element);\n            var choice = id && this._store.getChoiceById(id);\n            if (!choice || choice.disabled) {\n                return false;\n            }\n            var hasActiveDropdown = this.dropdown.isActive;\n            if (!choice.selected) {\n                if (!this._canAddItems()) {\n                    return true; // causes _onEnterKey to early out\n                }\n                this._store.withTxn(function () {\n                    _this._addItem(choice, true, true);\n                    _this.clearInput();\n                    _this.unhighlightAll();\n                });\n                this._triggerChange(choice.value);\n            }\n            // We want to close the dropdown if we are dealing with a single select box\n            if (hasActiveDropdown && this.config.closeDropdownOnSelect) {\n                this.hideDropdown(true);\n                this.containerOuter.element.focus();\n            }\n            return true;\n        };\n        Choices.prototype._handleBackspace = function (items) {\n            var config = this.config;\n            if (!config.removeItems || !items.length) {\n                return;\n            }\n            var lastItem = items[items.length - 1];\n            var hasHighlightedItems = items.some(function (item) { return item.highlighted; });\n            // If editing the last item is allowed and there are not other selected items,\n            // we can edit the item value. Otherwise if we can remove items, remove all selected items\n            if (config.editItems && !hasHighlightedItems && lastItem) {\n                this.input.value = lastItem.value;\n                this.input.setWidth();\n                this._removeItem(lastItem);\n                this._triggerChange(lastItem.value);\n            }\n            else {\n                if (!hasHighlightedItems) {\n                    // Highlight last item if none already highlighted\n                    this.highlightItem(lastItem, false);\n                }\n                this.removeHighlightedItems(true);\n            }\n        };\n        Choices.prototype._loadChoices = function () {\n            var _a;\n            var _this = this;\n            var config = this.config;\n            if (this._isTextElement) {\n                // Assign preset items from passed object first\n                this._presetChoices = config.items.map(function (e) { return mapInputToChoice(e, false); });\n                // Add any values passed from attribute\n                if (this.passedElement.value) {\n                    var elementItems = this.passedElement.value\n                        .split(config.delimiter)\n                        .map(function (e) { return mapInputToChoice(e, false, _this.config.allowHtmlUserInput); });\n                    this._presetChoices = this._presetChoices.concat(elementItems);\n                }\n                this._presetChoices.forEach(function (choice) {\n                    choice.selected = true;\n                });\n            }\n            else if (this._isSelectElement) {\n                // Assign preset choices from passed object\n                this._presetChoices = config.choices.map(function (e) { return mapInputToChoice(e, true); });\n                // Create array of choices from option elements\n                var choicesFromOptions = this.passedElement.optionsAsChoices();\n                if (choicesFromOptions) {\n                    (_a = this._presetChoices).push.apply(_a, choicesFromOptions);\n                }\n            }\n        };\n        Choices.prototype._handleLoadingState = function (setLoading) {\n            if (setLoading === void 0) { setLoading = true; }\n            var el = this.itemList.element;\n            if (setLoading) {\n                this.disable();\n                this.containerOuter.addLoadingState();\n                if (this._isSelectOneElement) {\n                    el.replaceChildren(this._templates.placeholder(this.config, this.config.loadingText));\n                }\n                else {\n                    this.input.placeholder = this.config.loadingText;\n                }\n            }\n            else {\n                this.enable();\n                this.containerOuter.removeLoadingState();\n                if (this._isSelectOneElement) {\n                    el.replaceChildren('');\n                    this._render();\n                }\n                else {\n                    this.input.placeholder = this._placeholderValue || '';\n                }\n            }\n        };\n        Choices.prototype._handleSearch = function (value) {\n            if (!this.input.isFocussed) {\n                return;\n            }\n            // Check that we have a value to search and the input was an alphanumeric character\n            if (value !== null && typeof value !== 'undefined' && value.length >= this.config.searchFloor) {\n                var resultCount = this.config.searchChoices ? this._searchChoices(value) : 0;\n                if (resultCount !== null) {\n                    // Trigger search event\n                    this.passedElement.triggerEvent(EventType.search, {\n                        value: value,\n                        resultCount: resultCount,\n                    });\n                }\n            }\n            else if (this._store.choices.some(function (option) { return !option.active; })) {\n                this._stopSearch();\n            }\n        };\n        Choices.prototype._canAddItems = function () {\n            var config = this.config;\n            var maxItemCount = config.maxItemCount, maxItemText = config.maxItemText;\n            if (!config.singleModeForMultiSelect && maxItemCount > 0 && maxItemCount <= this._store.items.length) {\n                this.choiceList.element.replaceChildren('');\n                this._notice = undefined;\n                this._displayNotice(typeof maxItemText === 'function' ? maxItemText(maxItemCount) : maxItemText, NoticeTypes.addChoice);\n                return false;\n            }\n            if (this._notice && this._notice.type === NoticeTypes.addChoice) {\n                this._clearNotice();\n            }\n            return true;\n        };\n        Choices.prototype._canCreateItem = function (value) {\n            var config = this.config;\n            var canAddItem = true;\n            var notice = '';\n            if (canAddItem && typeof config.addItemFilter === 'function' && !config.addItemFilter(value)) {\n                canAddItem = false;\n                notice = resolveNoticeFunction(config.customAddItemText, value, undefined);\n            }\n            if (canAddItem) {\n                var foundChoice = this._store.choices.find(function (choice) { return config.valueComparer(choice.value, value); });\n                if (foundChoice) {\n                    if (this._isSelectElement) {\n                        // for exact matches, do not prompt to add it as a custom choice\n                        this._displayNotice('', NoticeTypes.addChoice);\n                        return false;\n                    }\n                    if (!config.duplicateItemsAllowed) {\n                        canAddItem = false;\n                        notice = resolveNoticeFunction(config.uniqueItemText, value, undefined);\n                    }\n                }\n            }\n            if (canAddItem) {\n                notice = resolveNoticeFunction(config.addItemText, value, undefined);\n            }\n            if (notice) {\n                this._displayNotice(notice, NoticeTypes.addChoice);\n            }\n            return canAddItem;\n        };\n        Choices.prototype._searchChoices = function (value) {\n            var newValue = value.trim().replace(/\\s{2,}/, ' ');\n            // signal input didn't change search\n            if (!newValue.length || newValue === this._currentValue) {\n                return null;\n            }\n            var searcher = this._searcher;\n            if (searcher.isEmptyIndex()) {\n                searcher.index(this._store.searchableChoices);\n            }\n            // If new value matches the desired length and is not the same as the current value with a space\n            var results = searcher.search(newValue);\n            this._currentValue = newValue;\n            this._highlightPosition = 0;\n            this._isSearching = true;\n            var notice = this._notice;\n            var noticeType = notice && notice.type;\n            if (noticeType !== NoticeTypes.addChoice) {\n                if (!results.length) {\n                    this._displayNotice(resolveStringFunction(this.config.noResultsText), NoticeTypes.noResults);\n                }\n                else {\n                    this._clearNotice();\n                }\n            }\n            this._store.dispatch(filterChoices(results));\n            return results.length;\n        };\n        Choices.prototype._stopSearch = function () {\n            if (this._isSearching) {\n                this._currentValue = '';\n                this._isSearching = false;\n                this._clearNotice();\n                this._store.dispatch(activateChoices(true));\n                this.passedElement.triggerEvent(EventType.search, {\n                    value: '',\n                    resultCount: 0,\n                });\n            }\n        };\n        Choices.prototype._addEventListeners = function () {\n            var documentElement = this._docRoot;\n            var outerElement = this.containerOuter.element;\n            var inputElement = this.input.element;\n            var passedElement = this.passedElement.element;\n            // capture events - can cancel event processing or propagation\n            documentElement.addEventListener('touchend', this._onTouchEnd, true);\n            outerElement.addEventListener('keydown', this._onKeyDown, true);\n            outerElement.addEventListener('mousedown', this._onMouseDown, true);\n            // passive events - doesn't call `preventDefault` or `stopPropagation`\n            documentElement.addEventListener('click', this._onClick, { passive: true });\n            documentElement.addEventListener('touchmove', this._onTouchMove, {\n                passive: true,\n            });\n            this.dropdown.element.addEventListener('mouseover', this._onMouseOver, {\n                passive: true,\n            });\n            if (this._isSelectOneElement) {\n                outerElement.addEventListener('focus', this._onFocus, {\n                    passive: true,\n                });\n                outerElement.addEventListener('blur', this._onBlur, {\n                    passive: true,\n                });\n            }\n            inputElement.addEventListener('keyup', this._onKeyUp, {\n                passive: true,\n            });\n            inputElement.addEventListener('input', this._onInput, {\n                passive: true,\n            });\n            inputElement.addEventListener('focus', this._onFocus, {\n                passive: true,\n            });\n            inputElement.addEventListener('blur', this._onBlur, {\n                passive: true,\n            });\n            if (inputElement.form) {\n                inputElement.form.addEventListener('reset', this._onFormReset, {\n                    passive: true,\n                });\n            }\n            if (passedElement.hasAttribute('required')) {\n                passedElement.addEventListener('change', this._onChange, {\n                    passive: true,\n                });\n                passedElement.addEventListener('invalid', this._onInvalid, {\n                    passive: true,\n                });\n            }\n            this.input.addEventListeners();\n        };\n        Choices.prototype._removeEventListeners = function () {\n            var documentElement = this._docRoot;\n            var outerElement = this.containerOuter.element;\n            var inputElement = this.input.element;\n            var passedElement = this.passedElement.element;\n            documentElement.removeEventListener('touchend', this._onTouchEnd, true);\n            outerElement.removeEventListener('keydown', this._onKeyDown, true);\n            outerElement.removeEventListener('mousedown', this._onMouseDown, true);\n            documentElement.removeEventListener('click', this._onClick);\n            documentElement.removeEventListener('touchmove', this._onTouchMove);\n            this.dropdown.element.removeEventListener('mouseover', this._onMouseOver);\n            if (this._isSelectOneElement) {\n                outerElement.removeEventListener('focus', this._onFocus);\n                outerElement.removeEventListener('blur', this._onBlur);\n            }\n            inputElement.removeEventListener('keyup', this._onKeyUp);\n            inputElement.removeEventListener('input', this._onInput);\n            inputElement.removeEventListener('focus', this._onFocus);\n            inputElement.removeEventListener('blur', this._onBlur);\n            if (inputElement.form) {\n                inputElement.form.removeEventListener('reset', this._onFormReset);\n            }\n            if (passedElement.hasAttribute('required')) {\n                passedElement.removeEventListener('change', this._onChange);\n                passedElement.removeEventListener('invalid', this._onInvalid);\n            }\n            this.input.removeEventListeners();\n        };\n        Choices.prototype._onKeyDown = function (event) {\n            var keyCode = event.keyCode;\n            var hasActiveDropdown = this.dropdown.isActive;\n            /*\n            See:\n            https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key\n            https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values\n            https://en.wikipedia.org/wiki/UTF-16#Code_points_from_U+010000_to_U+10FFFF - UTF-16 surrogate pairs\n            https://stackoverflow.com/a/70866532 - \"Unidentified\" for mobile\n            http://www.unicode.org/versions/Unicode5.2.0/ch16.pdf#G19635 - U+FFFF is reserved (Section 16.7)\n        \n            Logic: when a key event is sent, `event.key` represents its printable value _or_ one\n            of a large list of special values indicating meta keys/functionality. In addition,\n            key events for compose functionality contain a value of `Dead` when mid-composition.\n        \n            I can't quite verify it, but non-English IMEs may also be able to generate key codes\n            for code points in the surrogate-pair range, which could potentially be seen as having\n            key.length > 1. Since `Fn` is one of the special keys, we can't distinguish by that\n            alone.\n        \n            Here, key.length === 1 means we know for sure the input was printable and not a special\n            `key` value. When the length is greater than 1, it could be either a printable surrogate\n            pair or a special `key` value. We can tell the difference by checking if the _character\n            code_ value (not code point!) is in the \"surrogate pair\" range or not.\n        \n            We don't use .codePointAt because an invalid code point would return 65535, which wouldn't\n            pass the >= 0x10000 check we would otherwise use.\n        \n            > ...The Unicode Standard sets aside 66 noncharacter code points. The last two code points\n            > of each plane are noncharacters: U+FFFE and U+FFFF on the BMP...\n            */\n            var wasPrintableChar = event.key.length === 1 ||\n                (event.key.length === 2 && event.key.charCodeAt(0) >= 0xd800) ||\n                event.key === 'Unidentified';\n            /*\n              We do not show the dropdown if focusing out with esc or navigating through input fields.\n              An activated search can still be opened with any other key.\n             */\n            if (!this._isTextElement &&\n                !hasActiveDropdown &&\n                keyCode !== KeyCodeMap.ESC_KEY &&\n                keyCode !== KeyCodeMap.TAB_KEY &&\n                keyCode !== KeyCodeMap.SHIFT_KEY) {\n                this.showDropdown();\n                if (!this.input.isFocussed && wasPrintableChar) {\n                    /*\n                      We update the input value with the pressed key as\n                      the input was not focussed at the time of key press\n                      therefore does not have the value of the key.\n                    */\n                    this.input.value += event.key;\n                    // browsers interpret a space as pagedown\n                    if (event.key === ' ') {\n                        event.preventDefault();\n                    }\n                }\n            }\n            switch (keyCode) {\n                case KeyCodeMap.A_KEY:\n                    return this._onSelectKey(event, this.itemList.element.hasChildNodes());\n                case KeyCodeMap.ENTER_KEY:\n                    return this._onEnterKey(event, hasActiveDropdown);\n                case KeyCodeMap.ESC_KEY:\n                    return this._onEscapeKey(event, hasActiveDropdown);\n                case KeyCodeMap.UP_KEY:\n                case KeyCodeMap.PAGE_UP_KEY:\n                case KeyCodeMap.DOWN_KEY:\n                case KeyCodeMap.PAGE_DOWN_KEY:\n                    return this._onDirectionKey(event, hasActiveDropdown);\n                case KeyCodeMap.DELETE_KEY:\n                case KeyCodeMap.BACK_KEY:\n                    return this._onDeleteKey(event, this._store.items, this.input.isFocussed);\n            }\n        };\n        Choices.prototype._onKeyUp = function ( /* event: KeyboardEvent */) {\n            this._canSearch = this.config.searchEnabled;\n        };\n        Choices.prototype._onInput = function ( /* event: InputEvent */) {\n            var value = this.input.value;\n            if (!value) {\n                if (this._isTextElement) {\n                    this.hideDropdown(true);\n                }\n                else {\n                    this._stopSearch();\n                }\n                return;\n            }\n            if (!this._canAddItems()) {\n                return;\n            }\n            if (this._canSearch) {\n                // do the search even if the entered text can not be added\n                this._handleSearch(value);\n            }\n            if (!this._canAddUserChoices) {\n                return;\n            }\n            // determine if a notice needs to be displayed for why a search result can't be added\n            this._canCreateItem(value);\n            if (this._isSelectElement) {\n                this._highlightPosition = 0; // reset to select the notice and/or exact match\n                this._highlightChoice();\n            }\n        };\n        Choices.prototype._onSelectKey = function (event, hasItems) {\n            // If CTRL + A or CMD + A have been pressed and there are items to select\n            if ((event.ctrlKey || event.metaKey) && hasItems) {\n                this._canSearch = false;\n                var shouldHightlightAll = this.config.removeItems && !this.input.value && this.input.element === document.activeElement;\n                if (shouldHightlightAll) {\n                    this.highlightAll();\n                }\n            }\n        };\n        Choices.prototype._onEnterKey = function (event, hasActiveDropdown) {\n            var _this = this;\n            var value = this.input.value;\n            var target = event.target;\n            event.preventDefault();\n            if (target && target.hasAttribute('data-button')) {\n                this._handleButtonAction(target);\n                return;\n            }\n            if (!hasActiveDropdown) {\n                if (this._isSelectElement || this._notice) {\n                    this.showDropdown();\n                }\n                return;\n            }\n            var highlightedChoice = this.dropdown.element.querySelector(getClassNamesSelector(this.config.classNames.highlightedState));\n            if (highlightedChoice && this._handleChoiceAction(highlightedChoice)) {\n                return;\n            }\n            if (!target || !value) {\n                this.hideDropdown(true);\n                return;\n            }\n            if (!this._canAddItems()) {\n                return;\n            }\n            var addedItem = false;\n            this._store.withTxn(function () {\n                addedItem = _this._findAndSelectChoiceByValue(value, true);\n                if (!addedItem) {\n                    if (!_this._canAddUserChoices) {\n                        return;\n                    }\n                    if (!_this._canCreateItem(value)) {\n                        return;\n                    }\n                    _this._addChoice(mapInputToChoice(value, false, _this.config.allowHtmlUserInput), true, true);\n                    addedItem = true;\n                }\n                _this.clearInput();\n                _this.unhighlightAll();\n            });\n            if (!addedItem) {\n                return;\n            }\n            this._triggerChange(value);\n            if (this.config.closeDropdownOnSelect) {\n                this.hideDropdown(true);\n            }\n        };\n        Choices.prototype._onEscapeKey = function (event, hasActiveDropdown) {\n            if (hasActiveDropdown) {\n                event.stopPropagation();\n                this.hideDropdown(true);\n                this._stopSearch();\n                this.containerOuter.element.focus();\n            }\n        };\n        Choices.prototype._onDirectionKey = function (event, hasActiveDropdown) {\n            var keyCode = event.keyCode;\n            // If up or down key is pressed, traverse through options\n            if (hasActiveDropdown || this._isSelectOneElement) {\n                this.showDropdown();\n                this._canSearch = false;\n                var directionInt = keyCode === KeyCodeMap.DOWN_KEY || keyCode === KeyCodeMap.PAGE_DOWN_KEY ? 1 : -1;\n                var skipKey = event.metaKey || keyCode === KeyCodeMap.PAGE_DOWN_KEY || keyCode === KeyCodeMap.PAGE_UP_KEY;\n                var nextEl = void 0;\n                if (skipKey) {\n                    if (directionInt > 0) {\n                        nextEl = this.dropdown.element.querySelector(\"\".concat(selectableChoiceIdentifier, \":last-of-type\"));\n                    }\n                    else {\n                        nextEl = this.dropdown.element.querySelector(selectableChoiceIdentifier);\n                    }\n                }\n                else {\n                    var currentEl = this.dropdown.element.querySelector(getClassNamesSelector(this.config.classNames.highlightedState));\n                    if (currentEl) {\n                        nextEl = getAdjacentEl(currentEl, selectableChoiceIdentifier, directionInt);\n                    }\n                    else {\n                        nextEl = this.dropdown.element.querySelector(selectableChoiceIdentifier);\n                    }\n                }\n                if (nextEl) {\n                    // We prevent default to stop the cursor moving\n                    // when pressing the arrow\n                    if (!isScrolledIntoView(nextEl, this.choiceList.element, directionInt)) {\n                        this.choiceList.scrollToChildElement(nextEl, directionInt);\n                    }\n                    this._highlightChoice(nextEl);\n                }\n                // Prevent default to maintain cursor position whilst\n                // traversing dropdown options\n                event.preventDefault();\n            }\n        };\n        Choices.prototype._onDeleteKey = function (event, items, hasFocusedInput) {\n            // If backspace or delete key is pressed and the input has no value\n            if (!this._isSelectOneElement && !event.target.value && hasFocusedInput) {\n                this._handleBackspace(items);\n                event.preventDefault();\n            }\n        };\n        Choices.prototype._onTouchMove = function () {\n            if (this._wasTap) {\n                this._wasTap = false;\n            }\n        };\n        Choices.prototype._onTouchEnd = function (event) {\n            var target = (event || event.touches[0]).target;\n            var touchWasWithinContainer = this._wasTap && this.containerOuter.element.contains(target);\n            if (touchWasWithinContainer) {\n                var containerWasExactTarget = target === this.containerOuter.element || target === this.containerInner.element;\n                if (containerWasExactTarget) {\n                    if (this._isTextElement) {\n                        this.input.focus();\n                    }\n                    else if (this._isSelectMultipleElement) {\n                        this.showDropdown();\n                    }\n                }\n                // Prevents focus event firing\n                event.stopPropagation();\n            }\n            this._wasTap = true;\n        };\n        /**\n         * Handles mousedown event in capture mode for containetOuter.element\n         */\n        Choices.prototype._onMouseDown = function (event) {\n            var target = event.target;\n            if (!(target instanceof Element)) {\n                return;\n            }\n            // If we have our mouse down on the scrollbar and are on IE11...\n            if (IS_IE11 && this.choiceList.element.contains(target)) {\n                // check if click was on a scrollbar area\n                var firstChoice = this.choiceList.element.firstElementChild;\n                this._isScrollingOnIe =\n                    this._direction === 'ltr' ? event.offsetX >= firstChoice.offsetWidth : event.offsetX < firstChoice.offsetLeft;\n            }\n            if (target === this.input.element) {\n                return;\n            }\n            var item = target.closest('[data-button],[data-item],[data-choice]');\n            if (item instanceof HTMLElement) {\n                if ('button' in item.dataset) {\n                    this._handleButtonAction(item);\n                }\n                else if ('item' in item.dataset) {\n                    this._handleItemAction(item, event.shiftKey);\n                }\n                else if ('choice' in item.dataset) {\n                    this._handleChoiceAction(item);\n                }\n            }\n            event.preventDefault();\n        };\n        /**\n         * Handles mouseover event over this.dropdown\n         * @param {MouseEvent} event\n         */\n        Choices.prototype._onMouseOver = function (_a) {\n            var target = _a.target;\n            if (target instanceof HTMLElement && 'choice' in target.dataset) {\n                this._highlightChoice(target);\n            }\n        };\n        Choices.prototype._onClick = function (_a) {\n            var target = _a.target;\n            var containerOuter = this.containerOuter;\n            var clickWasWithinContainer = containerOuter.element.contains(target);\n            if (clickWasWithinContainer) {\n                if (!this.dropdown.isActive && !containerOuter.isDisabled) {\n                    if (this._isTextElement) {\n                        if (document.activeElement !== this.input.element) {\n                            this.input.focus();\n                        }\n                    }\n                    else {\n                        this.showDropdown();\n                        containerOuter.element.focus();\n                    }\n                }\n                else if (this._isSelectOneElement &&\n                    target !== this.input.element &&\n                    !this.dropdown.element.contains(target)) {\n                    this.hideDropdown();\n                }\n            }\n            else {\n                containerOuter.removeFocusState();\n                this.hideDropdown(true);\n                this.unhighlightAll();\n            }\n        };\n        Choices.prototype._onFocus = function (_a) {\n            var target = _a.target;\n            var containerOuter = this.containerOuter;\n            var focusWasWithinContainer = target && containerOuter.element.contains(target);\n            if (!focusWasWithinContainer) {\n                return;\n            }\n            var targetIsInput = target === this.input.element;\n            if (this._isTextElement) {\n                if (targetIsInput) {\n                    containerOuter.addFocusState();\n                }\n            }\n            else if (this._isSelectMultipleElement) {\n                if (targetIsInput) {\n                    this.showDropdown(true);\n                    // If element is a select box, the focused element is the container and the dropdown\n                    // isn't already open, focus and show dropdown\n                    containerOuter.addFocusState();\n                }\n            }\n            else {\n                containerOuter.addFocusState();\n                if (targetIsInput) {\n                    this.showDropdown(true);\n                }\n            }\n        };\n        Choices.prototype._onBlur = function (_a) {\n            var target = _a.target;\n            var containerOuter = this.containerOuter;\n            var blurWasWithinContainer = target && containerOuter.element.contains(target);\n            if (blurWasWithinContainer && !this._isScrollingOnIe) {\n                if (target === this.input.element) {\n                    containerOuter.removeFocusState();\n                    this.hideDropdown(true);\n                    if (this._isTextElement || this._isSelectMultipleElement) {\n                        this.unhighlightAll();\n                    }\n                }\n                else if (target === this.containerOuter.element) {\n                    // Remove the focus state when the past outerContainer was the target\n                    containerOuter.removeFocusState();\n                    // Also close the dropdown if search is disabled\n                    if (!this.config.searchEnabled) {\n                        this.hideDropdown(true);\n                    }\n                }\n            }\n            else {\n                // On IE11, clicking the scollbar blurs our input and thus\n                // closes the dropdown. To stop this, we refocus our input\n                // if we know we are on IE *and* are scrolling.\n                this._isScrollingOnIe = false;\n                this.input.element.focus();\n            }\n        };\n        Choices.prototype._onFormReset = function () {\n            var _this = this;\n            this._store.withTxn(function () {\n                _this.clearInput();\n                _this.hideDropdown();\n                _this.refresh(false, false, true);\n                if (_this._initialItems.length) {\n                    _this.setChoiceByValue(_this._initialItems);\n                }\n            });\n        };\n        Choices.prototype._onChange = function (event) {\n            if (!event.target.checkValidity()) {\n                return;\n            }\n            this.containerOuter.removeInvalidState();\n        };\n        Choices.prototype._onInvalid = function () {\n            this.containerOuter.addInvalidState();\n        };\n        /**\n         * Removes any highlighted choice options\n         */\n        Choices.prototype._removeHighlightedChoices = function () {\n            var highlightedState = this.config.classNames.highlightedState;\n            var highlightedChoices = Array.from(this.dropdown.element.querySelectorAll(getClassNamesSelector(highlightedState)));\n            // Remove any highlighted choices\n            highlightedChoices.forEach(function (choice) {\n                removeClassesFromElement(choice, highlightedState);\n                choice.setAttribute('aria-selected', 'false');\n            });\n        };\n        Choices.prototype._highlightChoice = function (el) {\n            if (el === void 0) { el = null; }\n            var choices = Array.from(this.dropdown.element.querySelectorAll(selectableChoiceIdentifier));\n            if (!choices.length) {\n                return;\n            }\n            var passedEl = el;\n            var highlightedState = this.config.classNames.highlightedState;\n            this._removeHighlightedChoices();\n            if (passedEl) {\n                this._highlightPosition = choices.indexOf(passedEl);\n            }\n            else {\n                // Highlight choice based on last known highlight location\n                if (choices.length > this._highlightPosition) {\n                    // If we have an option to highlight\n                    passedEl = choices[this._highlightPosition];\n                }\n                else {\n                    // Otherwise highlight the option before\n                    passedEl = choices[choices.length - 1];\n                }\n                if (!passedEl) {\n                    passedEl = choices[0];\n                }\n            }\n            addClassesToElement(passedEl, highlightedState);\n            passedEl.setAttribute('aria-selected', 'true');\n            this.passedElement.triggerEvent(EventType.highlightChoice, {\n                el: passedEl,\n            });\n            if (this.dropdown.isActive) {\n                // IE11 ignores aria-label and blocks virtual keyboard\n                // if aria-activedescendant is set without a dropdown\n                this.input.setActiveDescendant(passedEl.id);\n                this.containerOuter.setActiveDescendant(passedEl.id);\n            }\n        };\n        Choices.prototype._addItem = function (item, withEvents, userTriggered) {\n            if (withEvents === void 0) { withEvents = true; }\n            if (userTriggered === void 0) { userTriggered = false; }\n            if (!item.id) {\n                throw new TypeError('item.id must be set before _addItem is called for a choice/item');\n            }\n            if (this.config.singleModeForMultiSelect || this._isSelectOneElement) {\n                this.removeActiveItems(item.id);\n            }\n            this._store.dispatch(addItem(item));\n            if (withEvents) {\n                var eventChoice = getChoiceForOutput(item);\n                this.passedElement.triggerEvent(EventType.addItem, eventChoice);\n                if (userTriggered) {\n                    this.passedElement.triggerEvent(EventType.choice, eventChoice);\n                }\n            }\n        };\n        Choices.prototype._removeItem = function (item) {\n            if (!item.id) {\n                return;\n            }\n            this._store.dispatch(removeItem$1(item));\n            var notice = this._notice;\n            if (notice && notice.type === NoticeTypes.noChoices) {\n                this._clearNotice();\n            }\n            this.passedElement.triggerEvent(EventType.removeItem, getChoiceForOutput(item));\n        };\n        Choices.prototype._addChoice = function (choice, withEvents, userTriggered) {\n            if (withEvents === void 0) { withEvents = true; }\n            if (userTriggered === void 0) { userTriggered = false; }\n            if (choice.id) {\n                throw new TypeError('Can not re-add a choice which has already been added');\n            }\n            var config = this.config;\n            if (!config.duplicateItemsAllowed && this._store.choices.find(function (c) { return config.valueComparer(c.value, choice.value); })) {\n                return;\n            }\n            // Generate unique id, in-place update is required so chaining _addItem works as expected\n            this._lastAddedChoiceId++;\n            choice.id = this._lastAddedChoiceId;\n            choice.elementId = \"\".concat(this._baseId, \"-\").concat(this._idNames.itemChoice, \"-\").concat(choice.id);\n            var prependValue = config.prependValue, appendValue = config.appendValue;\n            if (prependValue) {\n                choice.value = prependValue + choice.value;\n            }\n            if (appendValue) {\n                choice.value += appendValue.toString();\n            }\n            if ((prependValue || appendValue) && choice.element) {\n                choice.element.value = choice.value;\n            }\n            this._clearNotice();\n            this._store.dispatch(addChoice(choice));\n            if (choice.selected) {\n                this._addItem(choice, withEvents, userTriggered);\n            }\n        };\n        Choices.prototype._addGroup = function (group, withEvents) {\n            var _this = this;\n            if (withEvents === void 0) { withEvents = true; }\n            if (group.id) {\n                throw new TypeError('Can not re-add a group which has already been added');\n            }\n            this._store.dispatch(addGroup(group));\n            if (!group.choices) {\n                return;\n            }\n            // add unique id for the group(s), and do not store the full list of choices in this group\n            this._lastAddedGroupId++;\n            group.id = this._lastAddedGroupId;\n            group.choices.forEach(function (item) {\n                item.group = group;\n                if (group.disabled) {\n                    item.disabled = true;\n                }\n                _this._addChoice(item, withEvents);\n            });\n        };\n        Choices.prototype._createTemplates = function () {\n            var _this = this;\n            var callbackOnCreateTemplates = this.config.callbackOnCreateTemplates;\n            var userTemplates = {};\n            if (typeof callbackOnCreateTemplates === 'function') {\n                userTemplates = callbackOnCreateTemplates.call(this, strToEl, escapeForTemplate, getClassNames);\n            }\n            var templating = {};\n            Object.keys(this._templates).forEach(function (name) {\n                if (name in userTemplates) {\n                    templating[name] = userTemplates[name].bind(_this);\n                }\n                else {\n                    templating[name] = _this._templates[name].bind(_this);\n                }\n            });\n            this._templates = templating;\n        };\n        Choices.prototype._createElements = function () {\n            var templating = this._templates;\n            var _a = this, config = _a.config, isSelectOneElement = _a._isSelectOneElement;\n            var position = config.position, classNames = config.classNames;\n            var elementType = this._elementType;\n            this.containerOuter = new Container({\n                element: templating.containerOuter(config, this._direction, this._isSelectElement, isSelectOneElement, config.searchEnabled, elementType, config.labelId),\n                classNames: classNames,\n                type: elementType,\n                position: position,\n            });\n            this.containerInner = new Container({\n                element: templating.containerInner(config),\n                classNames: classNames,\n                type: elementType,\n                position: position,\n            });\n            this.input = new Input({\n                element: templating.input(config, this._placeholderValue),\n                classNames: classNames,\n                type: elementType,\n                preventPaste: !config.paste,\n            });\n            this.choiceList = new List({\n                element: templating.choiceList(config, isSelectOneElement),\n            });\n            this.itemList = new List({\n                element: templating.itemList(config, isSelectOneElement),\n            });\n            this.dropdown = new Dropdown({\n                element: templating.dropdown(config),\n                classNames: classNames,\n                type: elementType,\n            });\n        };\n        Choices.prototype._createStructure = function () {\n            var _a = this, containerInner = _a.containerInner, containerOuter = _a.containerOuter, passedElement = _a.passedElement;\n            var dropdownElement = this.dropdown.element;\n            // Hide original element\n            passedElement.conceal();\n            // Wrap input in container preserving DOM ordering\n            containerInner.wrap(passedElement.element);\n            // Wrapper inner container with outer container\n            containerOuter.wrap(containerInner.element);\n            containerOuter.element.appendChild(containerInner.element);\n            containerOuter.element.appendChild(dropdownElement);\n            containerInner.element.appendChild(this.itemList.element);\n            dropdownElement.appendChild(this.choiceList.element);\n            if (this._isSelectOneElement) {\n                this.input.placeholder = this.config.searchPlaceholderValue || '';\n                if (this.config.searchEnabled) {\n                    dropdownElement.insertBefore(this.input.element, dropdownElement.firstChild);\n                }\n            }\n            else {\n                if (!this._isSelectMultipleElement || this.config.searchEnabled) {\n                    containerInner.element.appendChild(this.input.element);\n                }\n                if (this._placeholderValue) {\n                    this.input.placeholder = this._placeholderValue;\n                }\n                this.input.setWidth();\n            }\n            this._highlightPosition = 0;\n            this._isSearching = false;\n        };\n        Choices.prototype._initStore = function () {\n            var _this = this;\n            this._store.subscribe(this._render).withTxn(function () {\n                _this._addPredefinedChoices(_this._presetChoices, _this._isSelectOneElement && !_this._hasNonChoicePlaceholder, false);\n            });\n            if (!this._store.choices.length || (this._isSelectOneElement && this._hasNonChoicePlaceholder)) {\n                this._render();\n            }\n        };\n        Choices.prototype._addPredefinedChoices = function (choices, selectFirstOption, withEvents) {\n            var _this = this;\n            if (selectFirstOption === void 0) { selectFirstOption = false; }\n            if (withEvents === void 0) { withEvents = true; }\n            if (selectFirstOption) {\n                /**\n                 * If there is a selected choice already or the choice is not the first in\n                 * the array, add each choice normally.\n                 *\n                 * Otherwise we pre-select the first enabled choice in the array (\"select-one\" only)\n                 */\n                var noSelectedChoices = choices.findIndex(function (choice) { return choice.selected; }) === -1;\n                if (noSelectedChoices) {\n                    choices.some(function (choice) {\n                        if (choice.disabled || 'choices' in choice) {\n                            return false;\n                        }\n                        choice.selected = true;\n                        return true;\n                    });\n                }\n            }\n            choices.forEach(function (item) {\n                if ('choices' in item) {\n                    if (_this._isSelectElement) {\n                        _this._addGroup(item, withEvents);\n                    }\n                }\n                else {\n                    _this._addChoice(item, withEvents);\n                }\n            });\n        };\n        Choices.prototype._findAndSelectChoiceByValue = function (value, userTriggered) {\n            var _this = this;\n            if (userTriggered === void 0) { userTriggered = false; }\n            // Check 'value' property exists and the choice isn't already selected\n            var foundChoice = this._store.choices.find(function (choice) { return _this.config.valueComparer(choice.value, value); });\n            if (foundChoice && !foundChoice.disabled && !foundChoice.selected) {\n                this._addItem(foundChoice, true, userTriggered);\n                return true;\n            }\n            return false;\n        };\n        Choices.prototype._generatePlaceholderValue = function () {\n            var config = this.config;\n            if (!config.placeholder) {\n                return null;\n            }\n            if (this._hasNonChoicePlaceholder) {\n                return config.placeholderValue;\n            }\n            if (this._isSelectElement) {\n                var placeholderOption = this.passedElement.placeholderOption;\n                return placeholderOption ? placeholderOption.text : null;\n            }\n            return null;\n        };\n        Choices.prototype._warnChoicesInitFailed = function (caller) {\n            if (this.config.silent) {\n                return;\n            }\n            if (!this.initialised) {\n                throw new TypeError(\"\".concat(caller, \" called on a non-initialised instance of Choices\"));\n            }\n            else if (!this.initialisedOK) {\n                throw new TypeError(\"\".concat(caller, \" called for an element which has multiple instances of Choices initialised on it\"));\n            }\n        };\n        Choices.version = '11.2.1';\n        return Choices;\n    }());\n\n    return Choices;\n\n}));\n"
  },
  {
    "path": "public/assets/scripts/choices.search-prefix.mjs",
    "content": "/*! choices.js v11.2.1 | © 2026 Josh Johnson | https://github.com/Choices-js/Choices#readme */\n\n/******************************************************************************\nCopyright (c) Microsoft Corporation.\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\nPERFORMANCE OF THIS SOFTWARE.\n***************************************************************************** */\n/* global Reflect, Promise, SuppressedError, Symbol */\n\nvar extendStatics = function (d, b) {\n  extendStatics = Object.setPrototypeOf || {\n    __proto__: []\n  } instanceof Array && function (d, b) {\n    d.__proto__ = b;\n  } || function (d, b) {\n    for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p];\n  };\n  return extendStatics(d, b);\n};\nfunction __extends(d, b) {\n  if (typeof b !== \"function\" && b !== null) throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\n  extendStatics(d, b);\n  function __() {\n    this.constructor = d;\n  }\n  d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\n}\nvar __assign = function () {\n  __assign = Object.assign || function __assign(t) {\n    for (var s, i = 1, n = arguments.length; i < n; i++) {\n      s = arguments[i];\n      for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\n    }\n    return t;\n  };\n  return __assign.apply(this, arguments);\n};\ntypeof SuppressedError === \"function\" ? SuppressedError : function (error, suppressed, message) {\n  var e = new Error(message);\n  return e.name = \"SuppressedError\", e.error = error, e.suppressed = suppressed, e;\n};\n\nvar ActionType = {\n    ADD_CHOICE: 'ADD_CHOICE',\n    REMOVE_CHOICE: 'REMOVE_CHOICE',\n    FILTER_CHOICES: 'FILTER_CHOICES',\n    ACTIVATE_CHOICES: 'ACTIVATE_CHOICES',\n    CLEAR_CHOICES: 'CLEAR_CHOICES',\n    ADD_GROUP: 'ADD_GROUP',\n    ADD_ITEM: 'ADD_ITEM',\n    REMOVE_ITEM: 'REMOVE_ITEM',\n    HIGHLIGHT_ITEM: 'HIGHLIGHT_ITEM',\n};\n\nvar EventType = {\n    showDropdown: 'showDropdown',\n    hideDropdown: 'hideDropdown',\n    change: 'change',\n    choice: 'choice',\n    search: 'search',\n    addItem: 'addItem',\n    removeItem: 'removeItem',\n    highlightItem: 'highlightItem',\n    highlightChoice: 'highlightChoice',\n    unhighlightItem: 'unhighlightItem',\n};\n\nvar KeyCodeMap = {\n    TAB_KEY: 9,\n    SHIFT_KEY: 16,\n    BACK_KEY: 46,\n    DELETE_KEY: 8,\n    ENTER_KEY: 13,\n    A_KEY: 65,\n    ESC_KEY: 27,\n    UP_KEY: 38,\n    DOWN_KEY: 40,\n    PAGE_UP_KEY: 33,\n    PAGE_DOWN_KEY: 34,\n};\n\nvar ObjectsInConfig = ['fuseOptions', 'classNames'];\n\nvar PassedElementTypes = {\n    Text: 'text',\n    SelectOne: 'select-one',\n    SelectMultiple: 'select-multiple',\n};\n\nvar addChoice = function (choice) { return ({\n    type: ActionType.ADD_CHOICE,\n    choice: choice,\n}); };\nvar removeChoice = function (choice) { return ({\n    type: ActionType.REMOVE_CHOICE,\n    choice: choice,\n}); };\nvar filterChoices = function (results) { return ({\n    type: ActionType.FILTER_CHOICES,\n    results: results,\n}); };\nvar activateChoices = function (active) {\n    return ({\n        type: ActionType.ACTIVATE_CHOICES,\n        active: active,\n    });\n};\n\nvar addGroup = function (group) { return ({\n    type: ActionType.ADD_GROUP,\n    group: group,\n}); };\n\nvar addItem = function (item) { return ({\n    type: ActionType.ADD_ITEM,\n    item: item,\n}); };\nvar removeItem$1 = function (item) { return ({\n    type: ActionType.REMOVE_ITEM,\n    item: item,\n}); };\nvar highlightItem = function (item, highlighted) { return ({\n    type: ActionType.HIGHLIGHT_ITEM,\n    item: item,\n    highlighted: highlighted,\n}); };\n\nvar getRandomNumber = function (min, max) { return Math.floor(Math.random() * (max - min) + min); };\nvar generateChars = function (length) {\n    return Array.from({ length: length }, function () { return getRandomNumber(0, 36).toString(36); }).join('');\n};\nvar generateId = function (element, prefix) {\n    var id = element.id || (element.name && \"\".concat(element.name, \"-\").concat(generateChars(2))) || generateChars(4);\n    id = id.replace(/(:|\\.|\\[|\\]|,)/g, '');\n    id = \"\".concat(prefix, \"-\").concat(id);\n    return id;\n};\nvar getAdjacentEl = function (startEl, selector, direction) {\n    if (direction === void 0) { direction = 1; }\n    var prop = \"\".concat(direction > 0 ? 'next' : 'previous', \"ElementSibling\");\n    var sibling = startEl[prop];\n    while (sibling) {\n        if (sibling.matches(selector)) {\n            return sibling;\n        }\n        sibling = sibling[prop];\n    }\n    return null;\n};\nvar isScrolledIntoView = function (element, parent, direction) {\n    if (direction === void 0) { direction = 1; }\n    var isVisible;\n    if (direction > 0) {\n        // In view from bottom\n        isVisible = parent.scrollTop + parent.offsetHeight >= element.offsetTop + element.offsetHeight;\n    }\n    else {\n        // In view from top\n        isVisible = element.offsetTop >= parent.scrollTop;\n    }\n    return isVisible;\n};\nvar sanitise = function (value) {\n    if (typeof value !== 'string') {\n        if (value === null || value === undefined) {\n            return '';\n        }\n        if (typeof value === 'object') {\n            if ('raw' in value) {\n                return sanitise(value.raw);\n            }\n            if ('trusted' in value) {\n                return value.trusted;\n            }\n        }\n        return value;\n    }\n    return value\n        .replace(/&/g, '&amp;')\n        .replace(/>/g, '&gt;')\n        .replace(/</g, '&lt;')\n        .replace(/'/g, '&#039;')\n        .replace(/\"/g, '&quot;');\n};\nvar strToEl = (function () {\n    var tmpEl = document.createElement('div');\n    return function (str) {\n        tmpEl.innerHTML = str.trim();\n        var firstChild = tmpEl.children[0];\n        while (tmpEl.firstChild) {\n            tmpEl.removeChild(tmpEl.firstChild);\n        }\n        return firstChild;\n    };\n})();\nvar resolveStringFunction = function (fn) {\n    return typeof fn === 'function' ? fn() : fn;\n};\nvar unwrapStringForRaw = function (s) {\n    if (typeof s === 'string') {\n        return s;\n    }\n    if (typeof s === 'object') {\n        if ('trusted' in s) {\n            return s.trusted;\n        }\n        if ('raw' in s) {\n            return s.raw;\n        }\n    }\n    return '';\n};\nvar unwrapStringForEscaped = function (s) {\n    if (typeof s === 'string') {\n        return s;\n    }\n    if (typeof s === 'object') {\n        if ('escaped' in s) {\n            return s.escaped;\n        }\n        if ('trusted' in s) {\n            return s.trusted;\n        }\n    }\n    return '';\n};\nvar getChoiceForOutput = function (choice, keyCode) {\n    return {\n        id: choice.id,\n        highlighted: choice.highlighted,\n        labelClass: choice.labelClass,\n        labelDescription: unwrapStringForRaw(choice.labelDescription),\n        customProperties: choice.customProperties,\n        disabled: choice.disabled,\n        active: choice.active,\n        label: choice.label,\n        placeholder: choice.placeholder,\n        value: choice.value,\n        groupValue: choice.group ? choice.group.label : undefined,\n        element: choice.element,\n        keyCode: keyCode,\n    };\n};\nvar resolveNoticeFunction = function (fn, value, item) {\n    return typeof fn === 'function' ? fn(sanitise(value), unwrapStringForRaw(value), item) : fn;\n};\nvar escapeForTemplate = function (allowHTML, s) {\n    return allowHTML ? unwrapStringForEscaped(s) : sanitise(s);\n};\nvar setElementHtml = function (el, allowHtml, html) {\n    el.innerHTML = escapeForTemplate(allowHtml, html);\n};\nvar sortByAlpha = function (_a, _b) {\n    var value = _a.value, _c = _a.label, label = _c === void 0 ? value : _c;\n    var value2 = _b.value, _d = _b.label, label2 = _d === void 0 ? value2 : _d;\n    return unwrapStringForRaw(label).localeCompare(unwrapStringForRaw(label2), [], {\n        sensitivity: 'base',\n        ignorePunctuation: true,\n        numeric: true,\n    });\n};\nvar sortByRank = function (a, b) {\n    return a.rank - b.rank;\n};\nvar dispatchEvent = function (element, type, customArgs) {\n    if (customArgs === void 0) { customArgs = null; }\n    var event = new CustomEvent(type, {\n        detail: customArgs,\n        bubbles: true,\n        cancelable: true,\n    });\n    return element.dispatchEvent(event);\n};\n/**\n * Returns an array of keys present on the first but missing on the second object\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nvar diff = function (a, b) {\n    var aKeys = Object.keys(a).sort();\n    var bKeys = Object.keys(b).sort();\n    return aKeys.filter(function (i) { return bKeys.indexOf(i) < 0; });\n};\nvar getClassNames = function (ClassNames) {\n    return Array.isArray(ClassNames) ? ClassNames : [ClassNames];\n};\nvar getClassNamesSelector = function (option) {\n    if (option && Array.isArray(option)) {\n        return option\n            .map(function (item) {\n            return \".\".concat(item);\n        })\n            .join('');\n    }\n    return \".\".concat(option);\n};\nvar addClassesToElement = function (element, className) {\n    var _a;\n    (_a = element.classList).add.apply(_a, getClassNames(className));\n};\nvar removeClassesFromElement = function (element, className) {\n    var _a;\n    (_a = element.classList).remove.apply(_a, getClassNames(className));\n};\nvar parseCustomProperties = function (customProperties) {\n    if (typeof customProperties !== 'undefined') {\n        try {\n            return JSON.parse(customProperties);\n        }\n        catch (e) {\n            return customProperties;\n        }\n    }\n    return {};\n};\nvar updateClassList = function (item, add, remove) {\n    var itemEl = item.itemEl;\n    if (itemEl) {\n        removeClassesFromElement(itemEl, remove);\n        addClassesToElement(itemEl, add);\n    }\n};\n\nvar Dropdown = /** @class */ (function () {\n    function Dropdown(_a) {\n        var element = _a.element, type = _a.type, classNames = _a.classNames;\n        this.element = element;\n        this.classNames = classNames;\n        this.type = type;\n        this.isActive = false;\n    }\n    /**\n     * Show dropdown to user by adding active state class\n     */\n    Dropdown.prototype.show = function () {\n        addClassesToElement(this.element, this.classNames.activeState);\n        this.element.setAttribute('aria-expanded', 'true');\n        this.isActive = true;\n        return this;\n    };\n    /**\n     * Hide dropdown from user\n     */\n    Dropdown.prototype.hide = function () {\n        removeClassesFromElement(this.element, this.classNames.activeState);\n        this.element.setAttribute('aria-expanded', 'false');\n        this.isActive = false;\n        return this;\n    };\n    return Dropdown;\n}());\n\nvar Container = /** @class */ (function () {\n    function Container(_a) {\n        var element = _a.element, type = _a.type, classNames = _a.classNames, position = _a.position;\n        this.element = element;\n        this.classNames = classNames;\n        this.type = type;\n        this.position = position;\n        this.isOpen = false;\n        this.isFlipped = false;\n        this.isDisabled = false;\n        this.isLoading = false;\n    }\n    /**\n     * Determine whether container should be flipped based on passed\n     * dropdown position\n     */\n    Container.prototype.shouldFlip = function (dropdownPos, dropdownHeight) {\n        // If flip is enabled and the dropdown bottom position is\n        // greater than the window height flip the dropdown.\n        var shouldFlip = false;\n        if (this.position === 'auto') {\n            shouldFlip =\n                this.element.getBoundingClientRect().top - dropdownHeight >= 0 &&\n                    !window.matchMedia(\"(min-height: \".concat(dropdownPos + 1, \"px)\")).matches;\n        }\n        else if (this.position === 'top') {\n            shouldFlip = true;\n        }\n        return shouldFlip;\n    };\n    Container.prototype.setActiveDescendant = function (activeDescendantID) {\n        this.element.setAttribute('aria-activedescendant', activeDescendantID);\n    };\n    Container.prototype.removeActiveDescendant = function () {\n        this.element.removeAttribute('aria-activedescendant');\n    };\n    Container.prototype.open = function (dropdownPos, dropdownHeight) {\n        addClassesToElement(this.element, this.classNames.openState);\n        this.element.setAttribute('aria-expanded', 'true');\n        this.isOpen = true;\n        if (this.shouldFlip(dropdownPos, dropdownHeight)) {\n            addClassesToElement(this.element, this.classNames.flippedState);\n            this.isFlipped = true;\n        }\n    };\n    Container.prototype.close = function () {\n        removeClassesFromElement(this.element, this.classNames.openState);\n        this.element.setAttribute('aria-expanded', 'false');\n        this.removeActiveDescendant();\n        this.isOpen = false;\n        // A dropdown flips if it does not have space within the page\n        if (this.isFlipped) {\n            removeClassesFromElement(this.element, this.classNames.flippedState);\n            this.isFlipped = false;\n        }\n    };\n    Container.prototype.addFocusState = function () {\n        addClassesToElement(this.element, this.classNames.focusState);\n    };\n    Container.prototype.removeFocusState = function () {\n        removeClassesFromElement(this.element, this.classNames.focusState);\n    };\n    Container.prototype.addInvalidState = function () {\n        addClassesToElement(this.element, this.classNames.invalidState);\n    };\n    Container.prototype.removeInvalidState = function () {\n        removeClassesFromElement(this.element, this.classNames.invalidState);\n    };\n    Container.prototype.enable = function () {\n        removeClassesFromElement(this.element, this.classNames.disabledState);\n        this.element.removeAttribute('aria-disabled');\n        if (this.type === PassedElementTypes.SelectOne) {\n            this.element.setAttribute('tabindex', '0');\n        }\n        this.isDisabled = false;\n    };\n    Container.prototype.disable = function () {\n        addClassesToElement(this.element, this.classNames.disabledState);\n        this.element.setAttribute('aria-disabled', 'true');\n        if (this.type === PassedElementTypes.SelectOne) {\n            this.element.setAttribute('tabindex', '-1');\n        }\n        this.isDisabled = true;\n    };\n    Container.prototype.wrap = function (element) {\n        var el = this.element;\n        var parentNode = element.parentNode;\n        if (parentNode) {\n            if (element.nextSibling) {\n                parentNode.insertBefore(el, element.nextSibling);\n            }\n            else {\n                parentNode.appendChild(el);\n            }\n        }\n        el.appendChild(element);\n    };\n    Container.prototype.unwrap = function (element) {\n        var el = this.element;\n        var parentNode = el.parentNode;\n        if (parentNode) {\n            // Move passed element outside this element\n            parentNode.insertBefore(element, el);\n            // Remove this element\n            parentNode.removeChild(el);\n        }\n    };\n    Container.prototype.addLoadingState = function () {\n        addClassesToElement(this.element, this.classNames.loadingState);\n        this.element.setAttribute('aria-busy', 'true');\n        this.isLoading = true;\n    };\n    Container.prototype.removeLoadingState = function () {\n        removeClassesFromElement(this.element, this.classNames.loadingState);\n        this.element.removeAttribute('aria-busy');\n        this.isLoading = false;\n    };\n    return Container;\n}());\n\nvar Input = /** @class */ (function () {\n    function Input(_a) {\n        var element = _a.element, type = _a.type, classNames = _a.classNames, preventPaste = _a.preventPaste;\n        this.element = element;\n        this.type = type;\n        this.classNames = classNames;\n        this.preventPaste = preventPaste;\n        this.isFocussed = this.element.isEqualNode(document.activeElement);\n        this.isDisabled = element.disabled;\n        this._onPaste = this._onPaste.bind(this);\n        this._onInput = this._onInput.bind(this);\n        this._onFocus = this._onFocus.bind(this);\n        this._onBlur = this._onBlur.bind(this);\n    }\n    Object.defineProperty(Input.prototype, \"placeholder\", {\n        set: function (placeholder) {\n            this.element.placeholder = placeholder;\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(Input.prototype, \"value\", {\n        get: function () {\n            return this.element.value;\n        },\n        set: function (value) {\n            this.element.value = value;\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Input.prototype.addEventListeners = function () {\n        var el = this.element;\n        el.addEventListener('paste', this._onPaste);\n        el.addEventListener('input', this._onInput, {\n            passive: true,\n        });\n        el.addEventListener('focus', this._onFocus, {\n            passive: true,\n        });\n        el.addEventListener('blur', this._onBlur, {\n            passive: true,\n        });\n    };\n    Input.prototype.removeEventListeners = function () {\n        var el = this.element;\n        el.removeEventListener('input', this._onInput);\n        el.removeEventListener('paste', this._onPaste);\n        el.removeEventListener('focus', this._onFocus);\n        el.removeEventListener('blur', this._onBlur);\n    };\n    Input.prototype.enable = function () {\n        var el = this.element;\n        el.removeAttribute('disabled');\n        this.isDisabled = false;\n    };\n    Input.prototype.disable = function () {\n        var el = this.element;\n        el.setAttribute('disabled', '');\n        this.isDisabled = true;\n    };\n    Input.prototype.focus = function () {\n        if (!this.isFocussed) {\n            this.element.focus();\n        }\n    };\n    Input.prototype.blur = function () {\n        if (this.isFocussed) {\n            this.element.blur();\n        }\n    };\n    Input.prototype.clear = function (setWidth) {\n        if (setWidth === void 0) { setWidth = true; }\n        this.element.value = '';\n        if (setWidth) {\n            this.setWidth();\n        }\n        return this;\n    };\n    /**\n     * Set the correct input width based on placeholder\n     * value or input value\n     */\n    Input.prototype.setWidth = function () {\n        // Resize input to contents or placeholder\n        var element = this.element;\n        element.style.minWidth = \"\".concat(element.placeholder.length + 1, \"ch\");\n        element.style.width = \"\".concat(element.value.length + 1, \"ch\");\n    };\n    Input.prototype.setActiveDescendant = function (activeDescendantID) {\n        this.element.setAttribute('aria-activedescendant', activeDescendantID);\n    };\n    Input.prototype.removeActiveDescendant = function () {\n        this.element.removeAttribute('aria-activedescendant');\n    };\n    Input.prototype._onInput = function () {\n        if (this.type !== PassedElementTypes.SelectOne) {\n            this.setWidth();\n        }\n    };\n    Input.prototype._onPaste = function (event) {\n        if (this.preventPaste) {\n            event.preventDefault();\n        }\n    };\n    Input.prototype._onFocus = function () {\n        this.isFocussed = true;\n    };\n    Input.prototype._onBlur = function () {\n        this.isFocussed = false;\n    };\n    return Input;\n}());\n\nvar SCROLLING_SPEED = 4;\n\nvar List = /** @class */ (function () {\n    function List(_a) {\n        var element = _a.element;\n        this.element = element;\n        this.scrollPos = this.element.scrollTop;\n        this.height = this.element.offsetHeight;\n    }\n    List.prototype.prepend = function (node) {\n        var child = this.element.firstElementChild;\n        if (child) {\n            this.element.insertBefore(node, child);\n        }\n        else {\n            this.element.append(node);\n        }\n    };\n    List.prototype.scrollToTop = function () {\n        this.element.scrollTop = 0;\n    };\n    List.prototype.scrollToChildElement = function (element, direction) {\n        var _this = this;\n        if (!element) {\n            return;\n        }\n        var listHeight = this.element.offsetHeight;\n        // Scroll position of dropdown\n        var listScrollPosition = this.element.scrollTop + listHeight;\n        var elementHeight = element.offsetHeight;\n        // Distance from bottom of element to top of parent\n        var elementPos = element.offsetTop + elementHeight;\n        // Difference between the element and scroll position\n        var destination = direction > 0 ? this.element.scrollTop + elementPos - listScrollPosition : element.offsetTop;\n        requestAnimationFrame(function () {\n            _this._animateScroll(destination, direction);\n        });\n    };\n    List.prototype._scrollDown = function (scrollPos, strength, destination) {\n        var easing = (destination - scrollPos) / strength;\n        var distance = easing > 1 ? easing : 1;\n        this.element.scrollTop = scrollPos + distance;\n    };\n    List.prototype._scrollUp = function (scrollPos, strength, destination) {\n        var easing = (scrollPos - destination) / strength;\n        var distance = easing > 1 ? easing : 1;\n        this.element.scrollTop = scrollPos - distance;\n    };\n    List.prototype._animateScroll = function (destination, direction) {\n        var _this = this;\n        var strength = SCROLLING_SPEED;\n        var choiceListScrollTop = this.element.scrollTop;\n        var continueAnimation = false;\n        if (direction > 0) {\n            this._scrollDown(choiceListScrollTop, strength, destination);\n            if (choiceListScrollTop < destination) {\n                continueAnimation = true;\n            }\n        }\n        else {\n            this._scrollUp(choiceListScrollTop, strength, destination);\n            if (choiceListScrollTop > destination) {\n                continueAnimation = true;\n            }\n        }\n        if (continueAnimation) {\n            requestAnimationFrame(function () {\n                _this._animateScroll(destination, direction);\n            });\n        }\n    };\n    return List;\n}());\n\nvar WrappedElement = /** @class */ (function () {\n    function WrappedElement(_a) {\n        var element = _a.element, classNames = _a.classNames;\n        this.element = element;\n        this.classNames = classNames;\n        this.isDisabled = false;\n    }\n    Object.defineProperty(WrappedElement.prototype, \"isActive\", {\n        get: function () {\n            return this.element.dataset.choice === 'active';\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(WrappedElement.prototype, \"dir\", {\n        get: function () {\n            return this.element.dir;\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(WrappedElement.prototype, \"value\", {\n        get: function () {\n            return this.element.value;\n        },\n        set: function (value) {\n            this.element.setAttribute('value', value);\n            this.element.value = value;\n        },\n        enumerable: false,\n        configurable: true\n    });\n    WrappedElement.prototype.conceal = function () {\n        var el = this.element;\n        // Hide passed input\n        addClassesToElement(el, this.classNames.input);\n        el.hidden = true;\n        // Remove element from tab index\n        el.tabIndex = -1;\n        // Backup original styles if any\n        var origStyle = el.getAttribute('style');\n        if (origStyle) {\n            el.setAttribute('data-choice-orig-style', origStyle);\n        }\n        el.setAttribute('data-choice', 'active');\n    };\n    WrappedElement.prototype.reveal = function () {\n        var el = this.element;\n        // Reinstate passed element\n        removeClassesFromElement(el, this.classNames.input);\n        el.hidden = false;\n        el.removeAttribute('tabindex');\n        // Recover original styles if any\n        var origStyle = el.getAttribute('data-choice-orig-style');\n        if (origStyle) {\n            el.removeAttribute('data-choice-orig-style');\n            el.setAttribute('style', origStyle);\n        }\n        else {\n            el.removeAttribute('style');\n        }\n        el.removeAttribute('data-choice');\n    };\n    WrappedElement.prototype.enable = function () {\n        this.element.removeAttribute('disabled');\n        this.element.disabled = false;\n        this.isDisabled = false;\n    };\n    WrappedElement.prototype.disable = function () {\n        this.element.setAttribute('disabled', '');\n        this.element.disabled = true;\n        this.isDisabled = true;\n    };\n    WrappedElement.prototype.triggerEvent = function (eventType, data) {\n        dispatchEvent(this.element, eventType, data || {});\n    };\n    return WrappedElement;\n}());\n\nvar WrappedInput = /** @class */ (function (_super) {\n    __extends(WrappedInput, _super);\n    function WrappedInput() {\n        return _super !== null && _super.apply(this, arguments) || this;\n    }\n    return WrappedInput;\n}(WrappedElement));\n\nvar coerceBool = function (arg, defaultValue) {\n    if (defaultValue === void 0) { defaultValue = true; }\n    return typeof arg === 'undefined' ? defaultValue : !!arg;\n};\nvar stringToHtmlClass = function (input) {\n    if (typeof input === 'string') {\n        // eslint-disable-next-line no-param-reassign\n        input = input.split(' ').filter(function (s) { return s.length; });\n    }\n    if (Array.isArray(input) && input.length) {\n        return input;\n    }\n    return undefined;\n};\nvar mapInputToChoice = function (value, allowGroup, allowRawString) {\n    if (allowRawString === void 0) { allowRawString = true; }\n    if (typeof value === 'string') {\n        var sanitisedValue = sanitise(value);\n        var userValue = allowRawString || sanitisedValue === value ? value : { escaped: sanitisedValue, raw: value };\n        var result_1 = mapInputToChoice({\n            value: value,\n            label: userValue,\n            selected: true,\n        }, false);\n        return result_1;\n    }\n    var groupOrChoice = value;\n    if ('choices' in groupOrChoice) {\n        if (!allowGroup) {\n            // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/optgroup\n            throw new TypeError(\"optGroup is not allowed\");\n        }\n        var group = groupOrChoice;\n        var choices = group.choices.map(function (e) { return mapInputToChoice(e, false); });\n        var result_2 = {\n            id: 0, // actual ID will be assigned during _addGroup\n            label: unwrapStringForRaw(group.label) || group.value,\n            active: !!choices.length,\n            disabled: !!group.disabled,\n            choices: choices,\n        };\n        return result_2;\n    }\n    var choice = groupOrChoice;\n    var result = {\n        id: 0, // actual ID will be assigned during _addChoice\n        group: null, // actual group will be assigned during _addGroup but before _addChoice\n        score: 0, // used in search\n        rank: 0, // used in search, stable sort order\n        value: choice.value,\n        label: choice.label || choice.value,\n        active: coerceBool(choice.active),\n        selected: coerceBool(choice.selected, false),\n        disabled: coerceBool(choice.disabled, false),\n        placeholder: coerceBool(choice.placeholder, false),\n        highlighted: false,\n        labelClass: stringToHtmlClass(choice.labelClass),\n        labelDescription: choice.labelDescription,\n        customProperties: choice.customProperties,\n    };\n    return result;\n};\n\nvar isHtmlInputElement = function (e) { return e.tagName === 'INPUT'; };\nvar isHtmlSelectElement = function (e) { return e.tagName === 'SELECT'; };\nvar isHtmlOption = function (e) { return e.tagName === 'OPTION'; };\nvar isHtmlOptgroup = function (e) { return e.tagName === 'OPTGROUP'; };\n\nvar WrappedSelect = /** @class */ (function (_super) {\n    __extends(WrappedSelect, _super);\n    function WrappedSelect(_a) {\n        var element = _a.element, classNames = _a.classNames, template = _a.template, extractPlaceholder = _a.extractPlaceholder;\n        var _this = _super.call(this, { element: element, classNames: classNames }) || this;\n        _this.template = template;\n        _this.extractPlaceholder = extractPlaceholder;\n        return _this;\n    }\n    Object.defineProperty(WrappedSelect.prototype, \"placeholderOption\", {\n        get: function () {\n            return (this.element.querySelector('option[value=\"\"]') ||\n                // Backward compatibility layer for the non-standard placeholder attribute supported in older versions.\n                this.element.querySelector('option[placeholder]'));\n        },\n        enumerable: false,\n        configurable: true\n    });\n    WrappedSelect.prototype.addOptions = function (choices) {\n        var _this = this;\n        var fragment = document.createDocumentFragment();\n        choices.forEach(function (obj) {\n            var choice = obj;\n            if (choice.element) {\n                return;\n            }\n            var option = _this.template(choice);\n            fragment.appendChild(option);\n            choice.element = option;\n        });\n        this.element.appendChild(fragment);\n    };\n    WrappedSelect.prototype.optionsAsChoices = function () {\n        var _this = this;\n        var choices = [];\n        this.element.querySelectorAll(':scope > option, :scope > optgroup').forEach(function (e) {\n            if (isHtmlOption(e)) {\n                choices.push(_this._optionToChoice(e));\n            }\n            else if (isHtmlOptgroup(e)) {\n                choices.push(_this._optgroupToChoice(e));\n            }\n            // todo: hr as empty optgroup, requires displaying empty opt-groups to be useful\n        });\n        return choices;\n    };\n    // eslint-disable-next-line class-methods-use-this\n    WrappedSelect.prototype._optionToChoice = function (option) {\n        // option.value returns the label if there is no value attribute, which can break legacy placeholder attribute support\n        if (!option.hasAttribute('value') && option.hasAttribute('placeholder')) {\n            option.setAttribute('value', '');\n            option.value = '';\n        }\n        return {\n            id: 0,\n            group: null,\n            score: 0,\n            rank: 0,\n            value: option.value,\n            // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/option\n            // This attribute is text for the label indicating the meaning of the option. If the `label` attribute isn't defined, its value is that of the element text content (ie `innerText`).\n            label: option.label,\n            element: option,\n            active: true,\n            // this returns true if nothing is selected on initial load, which will break placeholder support\n            selected: this.extractPlaceholder ? option.selected : option.hasAttribute('selected'),\n            disabled: option.disabled,\n            highlighted: false,\n            placeholder: this.extractPlaceholder && (!option.value || option.hasAttribute('placeholder')),\n            labelClass: typeof option.dataset.labelClass !== 'undefined' ? stringToHtmlClass(option.dataset.labelClass) : undefined,\n            labelDescription: typeof option.dataset.labelDescription !== 'undefined'\n                ? { trusted: option.dataset.labelDescription }\n                : undefined,\n            customProperties: parseCustomProperties(option.dataset.customProperties),\n        };\n    };\n    WrappedSelect.prototype._optgroupToChoice = function (optgroup) {\n        var _this = this;\n        var options = optgroup.querySelectorAll('option');\n        var choices = Array.from(options).map(function (option) { return _this._optionToChoice(option); });\n        return {\n            id: 0,\n            label: optgroup.label || '',\n            element: optgroup,\n            active: !!choices.length,\n            disabled: optgroup.disabled,\n            choices: choices,\n        };\n    };\n    return WrappedSelect;\n}(WrappedElement));\n\nvar DEFAULT_CLASSNAMES = {\n    containerOuter: ['choices'],\n    containerInner: ['choices__inner'],\n    input: ['choices__input'],\n    inputCloned: ['choices__input--cloned'],\n    list: ['choices__list'],\n    listItems: ['choices__list--multiple'],\n    listSingle: ['choices__list--single'],\n    listDropdown: ['choices__list--dropdown'],\n    item: ['choices__item'],\n    itemSelectable: ['choices__item--selectable'],\n    itemDisabled: ['choices__item--disabled'],\n    itemChoice: ['choices__item--choice'],\n    description: ['choices__description'],\n    placeholder: ['choices__placeholder'],\n    group: ['choices__group'],\n    groupHeading: ['choices__heading'],\n    button: ['choices__button'],\n    activeState: ['is-active'],\n    focusState: ['is-focused'],\n    openState: ['is-open'],\n    disabledState: ['is-disabled'],\n    highlightedState: ['is-highlighted'],\n    selectedState: ['is-selected'],\n    flippedState: ['is-flipped'],\n    loadingState: ['is-loading'],\n    invalidState: ['is-invalid'],\n    notice: ['choices__notice'],\n    addChoice: ['choices__item--selectable', 'add-choice'],\n    noResults: ['has-no-results'],\n    noChoices: ['has-no-choices'],\n};\nvar DEFAULT_CONFIG = {\n    items: [],\n    choices: [],\n    silent: false,\n    renderChoiceLimit: -1,\n    maxItemCount: -1,\n    closeDropdownOnSelect: 'auto',\n    singleModeForMultiSelect: false,\n    addChoices: false,\n    addItems: true,\n    addItemFilter: function (value) { return !!value && value !== ''; },\n    removeItems: true,\n    removeItemButton: false,\n    removeItemButtonAlignLeft: false,\n    editItems: false,\n    allowHTML: false,\n    allowHtmlUserInput: false,\n    duplicateItemsAllowed: true,\n    delimiter: ',',\n    paste: true,\n    searchEnabled: true,\n    searchChoices: true,\n    searchDisabledChoices: false,\n    searchFloor: 1,\n    searchResultLimit: 4,\n    searchFields: ['label', 'value'],\n    position: 'auto',\n    resetScrollPosition: true,\n    shouldSort: true,\n    shouldSortItems: false,\n    sorter: sortByAlpha,\n    shadowRoot: null,\n    placeholder: true,\n    placeholderValue: null,\n    searchPlaceholderValue: null,\n    prependValue: null,\n    appendValue: null,\n    renderSelectedChoices: 'auto',\n    searchRenderSelectedChoices: true,\n    loadingText: 'Loading...',\n    noResultsText: 'No results found',\n    noChoicesText: 'No choices to choose from',\n    itemSelectText: 'Press to select',\n    uniqueItemText: 'Only unique values can be added',\n    customAddItemText: 'Only values matching specific conditions can be added',\n    addItemText: function (value) { return \"Press Enter to add <b>\\\"\".concat(value, \"\\\"</b>\"); },\n    removeItemIconText: function () { return \"Remove item\"; },\n    removeItemLabelText: function (value, _valueRaw, i) {\n        return \"Remove item: \".concat(i ? sanitise(i.label) : value);\n    },\n    maxItemText: function (maxItemCount) { return \"Only \".concat(maxItemCount, \" values can be added\"); },\n    valueComparer: function (value1, value2) { return value1 === value2; },\n    fuseOptions: {\n        includeScore: true,\n    },\n    labelId: '',\n    callbackOnInit: null,\n    callbackOnCreateTemplates: null,\n    classNames: DEFAULT_CLASSNAMES,\n    appendGroupInSearch: false,\n};\n\nvar removeItem = function (item) {\n    var itemEl = item.itemEl;\n    if (itemEl) {\n        itemEl.remove();\n        item.itemEl = undefined;\n    }\n};\nfunction items(s, action, context) {\n    var state = s;\n    var update = true;\n    switch (action.type) {\n        case ActionType.ADD_ITEM: {\n            action.item.selected = true;\n            var el = action.item.element;\n            if (el) {\n                el.selected = true;\n                el.setAttribute('selected', '');\n            }\n            state.push(action.item);\n            break;\n        }\n        case ActionType.REMOVE_ITEM: {\n            action.item.selected = false;\n            var el = action.item.element;\n            if (el) {\n                el.selected = false;\n                el.removeAttribute('selected');\n                // For a select-one, if all options are deselected, the first item is selected. To set a black value, select.value needs to be set\n                var select = el.parentElement;\n                if (select && isHtmlSelectElement(select) && select.type === PassedElementTypes.SelectOne) {\n                    select.value = '';\n                }\n            }\n            // this is mixing concerns, but this is *so much faster*\n            removeItem(action.item);\n            state = state.filter(function (choice) { return choice.id !== action.item.id; });\n            break;\n        }\n        case ActionType.REMOVE_CHOICE: {\n            removeItem(action.choice);\n            state = state.filter(function (item) { return item.id !== action.choice.id; });\n            break;\n        }\n        case ActionType.HIGHLIGHT_ITEM: {\n            var highlighted = action.highlighted;\n            var item = state.find(function (obj) { return obj.id === action.item.id; });\n            if (item && item.highlighted !== highlighted) {\n                item.highlighted = highlighted;\n                if (context) {\n                    updateClassList(item, highlighted ? context.classNames.highlightedState : context.classNames.selectedState, highlighted ? context.classNames.selectedState : context.classNames.highlightedState);\n                }\n            }\n            break;\n        }\n        default: {\n            update = false;\n            break;\n        }\n    }\n    return { state: state, update: update };\n}\n\nfunction groups(s, action) {\n    var state = s;\n    var update = true;\n    switch (action.type) {\n        case ActionType.ADD_GROUP: {\n            state.push(action.group);\n            break;\n        }\n        case ActionType.CLEAR_CHOICES: {\n            state = [];\n            break;\n        }\n        default: {\n            update = false;\n            break;\n        }\n    }\n    return { state: state, update: update };\n}\n\n/* eslint-disable */\nfunction choices(s, action, context) {\n    var state = s;\n    var update = true;\n    switch (action.type) {\n        case ActionType.ADD_CHOICE: {\n            state.push(action.choice);\n            break;\n        }\n        case ActionType.REMOVE_CHOICE: {\n            action.choice.choiceEl = undefined;\n            if (action.choice.group) {\n                action.choice.group.choices = action.choice.group.choices.filter(function (obj) { return obj.id !== action.choice.id; });\n            }\n            state = state.filter(function (obj) { return obj.id !== action.choice.id; });\n            break;\n        }\n        case ActionType.ADD_ITEM:\n        case ActionType.REMOVE_ITEM: {\n            action.item.choiceEl = undefined;\n            break;\n        }\n        case ActionType.FILTER_CHOICES: {\n            // avoid O(n^2) algorithm complexity when searching/filtering choices\n            var scoreLookup_1 = [];\n            action.results.forEach(function (result) {\n                scoreLookup_1[result.item.id] = result;\n            });\n            state.forEach(function (choice) {\n                var result = scoreLookup_1[choice.id];\n                if (result !== undefined) {\n                    choice.score = result.score;\n                    choice.rank = result.rank;\n                    choice.active = true;\n                }\n                else {\n                    choice.score = 0;\n                    choice.rank = 0;\n                    choice.active = false;\n                }\n                if (context && context.appendGroupInSearch) {\n                    choice.choiceEl = undefined;\n                }\n            });\n            break;\n        }\n        case ActionType.ACTIVATE_CHOICES: {\n            state.forEach(function (choice) {\n                choice.active = action.active;\n                if (context && context.appendGroupInSearch) {\n                    choice.choiceEl = undefined;\n                }\n            });\n            break;\n        }\n        case ActionType.CLEAR_CHOICES: {\n            state = [];\n            break;\n        }\n        default: {\n            update = false;\n            break;\n        }\n    }\n    return { state: state, update: update };\n}\n\nvar reducers = {\n    groups: groups,\n    items: items,\n    choices: choices,\n};\nvar Store = /** @class */ (function () {\n    function Store(context) {\n        this._state = this.defaultState;\n        this._listeners = [];\n        this._txn = 0;\n        this._context = context;\n    }\n    Object.defineProperty(Store.prototype, \"defaultState\", {\n        // eslint-disable-next-line class-methods-use-this\n        get: function () {\n            return {\n                groups: [],\n                items: [],\n                choices: [],\n            };\n        },\n        enumerable: false,\n        configurable: true\n    });\n    // eslint-disable-next-line class-methods-use-this\n    Store.prototype.changeSet = function (init) {\n        return {\n            groups: init,\n            items: init,\n            choices: init,\n        };\n    };\n    Store.prototype.reset = function () {\n        this._state = this.defaultState;\n        var changes = this.changeSet(true);\n        if (this._txn) {\n            this._changeSet = changes;\n        }\n        else {\n            this._listeners.forEach(function (l) { return l(changes); });\n        }\n    };\n    Store.prototype.subscribe = function (onChange) {\n        this._listeners.push(onChange);\n        return this;\n    };\n    Store.prototype.dispatch = function (action) {\n        var _this = this;\n        var state = this._state;\n        var hasChanges = false;\n        var changes = this._changeSet || this.changeSet(false);\n        Object.keys(reducers).forEach(function (key) {\n            var stateUpdate = reducers[key](state[key], action, _this._context);\n            if (stateUpdate.update) {\n                hasChanges = true;\n                changes[key] = true;\n                state[key] = stateUpdate.state;\n            }\n        });\n        if (hasChanges) {\n            if (this._txn) {\n                this._changeSet = changes;\n            }\n            else {\n                this._listeners.forEach(function (l) { return l(changes); });\n            }\n        }\n    };\n    Store.prototype.withTxn = function (func) {\n        this._txn++;\n        try {\n            func();\n        }\n        finally {\n            this._txn = Math.max(0, this._txn - 1);\n            if (!this._txn) {\n                var changeSet_1 = this._changeSet;\n                if (changeSet_1) {\n                    this._changeSet = undefined;\n                    this._listeners.forEach(function (l) { return l(changeSet_1); });\n                }\n            }\n        }\n    };\n    Object.defineProperty(Store.prototype, \"state\", {\n        /**\n         * Get store object\n         */\n        get: function () {\n            return this._state;\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(Store.prototype, \"items\", {\n        /**\n         * Get items from store\n         */\n        get: function () {\n            return this.state.items;\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(Store.prototype, \"highlightedActiveItems\", {\n        /**\n         * Get highlighted items from store\n         */\n        get: function () {\n            return this.items.filter(function (item) { return item.active && item.highlighted; });\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(Store.prototype, \"choices\", {\n        /**\n         * Get choices from store\n         */\n        get: function () {\n            return this.state.choices;\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(Store.prototype, \"activeChoices\", {\n        /**\n         * Get active choices from store\n         */\n        get: function () {\n            return this.choices.filter(function (choice) { return choice.active; });\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(Store.prototype, \"searchableChoices\", {\n        /**\n         * Get choices that can be searched (excluding placeholders or disabled choices)\n         */\n        get: function () {\n            var context = this._context;\n            return this.choices.filter(function (choice) { return !choice.placeholder && (context.searchDisabledChoices || !choice.disabled); });\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(Store.prototype, \"groups\", {\n        /**\n         * Get groups from store\n         */\n        get: function () {\n            return this.state.groups;\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Object.defineProperty(Store.prototype, \"activeGroups\", {\n        /**\n         * Get active groups from store\n         */\n        get: function () {\n            var _this = this;\n            return this.state.groups.filter(function (group) {\n                var isActive = group.active && !group.disabled;\n                var hasActiveOptions = _this.state.choices.some(function (choice) { return choice.active && !choice.disabled; });\n                return isActive && hasActiveOptions;\n            }, []);\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Store.prototype.inTxn = function () {\n        return this._txn > 0;\n    };\n    /**\n     * Get single choice by it's ID\n     */\n    Store.prototype.getChoiceById = function (id) {\n        return this.activeChoices.find(function (choice) { return choice.id === id; });\n    };\n    /**\n     * Get group by group id\n     */\n    Store.prototype.getGroupById = function (id) {\n        return this.groups.find(function (group) { return group.id === id; });\n    };\n    return Store;\n}());\n\nvar NoticeTypes = {\n    noChoices: 'no-choices',\n    noResults: 'no-results',\n    addChoice: 'add-choice',\n    generic: '',\n};\n\nvar SearchByPrefixFilter = /** @class */ (function () {\n    function SearchByPrefixFilter(config) {\n        this._haystack = [];\n        this._fields = config.searchFields;\n    }\n    SearchByPrefixFilter.prototype.index = function (data) {\n        this._haystack = data;\n    };\n    SearchByPrefixFilter.prototype.reset = function () {\n        this._haystack = [];\n    };\n    SearchByPrefixFilter.prototype.isEmptyIndex = function () {\n        return !this._haystack.length;\n    };\n    SearchByPrefixFilter.prototype.search = function (_needle) {\n        var fields = this._fields;\n        if (!fields || !fields.length || !_needle) {\n            return [];\n        }\n        var needle = _needle.toLowerCase();\n        return this._haystack\n            .filter(function (obj) { return fields.some(function (field) { return field in obj && obj[field].toLowerCase().startsWith(needle); }); })\n            .map(function (value, index) {\n            return {\n                item: value,\n                score: index,\n                rank: index + 1,\n            };\n        });\n    };\n    return SearchByPrefixFilter;\n}());\n\nfunction getSearcher(config) {\n    return new SearchByPrefixFilter(config);\n}\n\n/**\n * Helpers to create HTML elements used by Choices\n * Can be overridden by providing `callbackOnCreateTemplates` option.\n * `Choices.defaults.templates` allows access to the default template methods from `callbackOnCreateTemplates`\n */\nvar isEmptyObject = function (obj) {\n    // eslint-disable-next-line no-restricted-syntax\n    for (var prop in obj) {\n        if (Object.prototype.hasOwnProperty.call(obj, prop)) {\n            return false;\n        }\n    }\n    return true;\n};\nvar assignCustomProperties = function (el, choice, withCustomProperties) {\n    var dataset = el.dataset;\n    var customProperties = choice.customProperties, labelClass = choice.labelClass, labelDescription = choice.labelDescription;\n    if (labelClass) {\n        dataset.labelClass = getClassNames(labelClass).join(' ');\n    }\n    if (labelDescription) {\n        dataset.labelDescription = unwrapStringForRaw(labelDescription);\n    }\n    if (withCustomProperties && customProperties) {\n        if (typeof customProperties === 'string') {\n            dataset.customProperties = customProperties;\n        }\n        else if (typeof customProperties === 'object' && !isEmptyObject(customProperties)) {\n            dataset.customProperties = JSON.stringify(customProperties);\n        }\n    }\n};\nvar addAriaLabel = function (docRoot, id, element) {\n    var label = id && docRoot.querySelector(\"label[for='\".concat(id, \"']\"));\n    var text = label && label.innerText;\n    if (text) {\n        element.setAttribute('aria-label', text);\n    }\n};\nvar templates = {\n    containerOuter: function (_a, dir, isSelectElement, isSelectOneElement, searchEnabled, passedElementType, labelId) {\n        var containerOuter = _a.classNames.containerOuter;\n        var div = document.createElement('div');\n        addClassesToElement(div, containerOuter);\n        div.dataset.type = passedElementType;\n        if (dir) {\n            div.dir = dir;\n        }\n        if (isSelectOneElement) {\n            div.tabIndex = 0;\n        }\n        if (isSelectElement) {\n            div.setAttribute('role', searchEnabled ? 'combobox' : 'listbox');\n            if (searchEnabled) {\n                div.setAttribute('aria-autocomplete', 'list');\n            }\n            else if (!labelId) {\n                addAriaLabel(this._docRoot, this.passedElement.element.id, div);\n            }\n            div.setAttribute('aria-haspopup', 'true');\n            div.setAttribute('aria-expanded', 'false');\n        }\n        if (labelId) {\n            div.setAttribute('aria-labelledby', labelId);\n        }\n        return div;\n    },\n    containerInner: function (_a) {\n        var containerInner = _a.classNames.containerInner;\n        var div = document.createElement('div');\n        addClassesToElement(div, containerInner);\n        return div;\n    },\n    itemList: function (_a, isSelectOneElement) {\n        var searchEnabled = _a.searchEnabled, _b = _a.classNames, list = _b.list, listSingle = _b.listSingle, listItems = _b.listItems;\n        var div = document.createElement('div');\n        addClassesToElement(div, list);\n        addClassesToElement(div, isSelectOneElement ? listSingle : listItems);\n        if (this._isSelectElement && searchEnabled) {\n            div.setAttribute('role', 'listbox');\n        }\n        return div;\n    },\n    placeholder: function (_a, value) {\n        var allowHTML = _a.allowHTML, placeholder = _a.classNames.placeholder;\n        var div = document.createElement('div');\n        addClassesToElement(div, placeholder);\n        setElementHtml(div, allowHTML, value);\n        return div;\n    },\n    item: function (_a, choice, removeItemButton) {\n        var allowHTML = _a.allowHTML, removeItemButtonAlignLeft = _a.removeItemButtonAlignLeft, removeItemIconText = _a.removeItemIconText, removeItemLabelText = _a.removeItemLabelText, _b = _a.classNames, item = _b.item, button = _b.button, highlightedState = _b.highlightedState, itemSelectable = _b.itemSelectable, placeholder = _b.placeholder;\n        var rawValue = unwrapStringForRaw(choice.value);\n        var div = document.createElement('div');\n        addClassesToElement(div, item);\n        if (choice.labelClass) {\n            var spanLabel = document.createElement('span');\n            setElementHtml(spanLabel, allowHTML, choice.label);\n            addClassesToElement(spanLabel, choice.labelClass);\n            div.appendChild(spanLabel);\n        }\n        else {\n            setElementHtml(div, allowHTML, choice.label);\n        }\n        div.dataset.item = '';\n        div.dataset.id = choice.id;\n        div.dataset.value = rawValue;\n        assignCustomProperties(div, choice, true);\n        if (choice.disabled || this.containerOuter.isDisabled) {\n            div.setAttribute('aria-disabled', 'true');\n        }\n        if (this._isSelectElement) {\n            div.setAttribute('aria-selected', 'true');\n            div.setAttribute('role', 'option');\n        }\n        if (choice.placeholder) {\n            addClassesToElement(div, placeholder);\n            div.dataset.placeholder = '';\n        }\n        addClassesToElement(div, choice.highlighted ? highlightedState : itemSelectable);\n        if (removeItemButton) {\n            if (choice.disabled) {\n                removeClassesFromElement(div, itemSelectable);\n            }\n            div.dataset.deletable = '';\n            var removeButton = document.createElement('button');\n            removeButton.type = 'button';\n            addClassesToElement(removeButton, button);\n            var eventChoice = getChoiceForOutput(choice);\n            setElementHtml(removeButton, true, resolveNoticeFunction(removeItemIconText, choice.value, eventChoice));\n            var REMOVE_ITEM_LABEL = resolveNoticeFunction(removeItemLabelText, choice.value, eventChoice);\n            if (REMOVE_ITEM_LABEL) {\n                removeButton.setAttribute('aria-label', REMOVE_ITEM_LABEL);\n            }\n            removeButton.dataset.button = '';\n            if (removeItemButtonAlignLeft) {\n                div.insertAdjacentElement('afterbegin', removeButton);\n            }\n            else {\n                div.appendChild(removeButton);\n            }\n        }\n        return div;\n    },\n    choiceList: function (_a, isSelectOneElement) {\n        var list = _a.classNames.list;\n        var div = document.createElement('div');\n        addClassesToElement(div, list);\n        if (!isSelectOneElement) {\n            div.setAttribute('aria-multiselectable', 'true');\n        }\n        div.setAttribute('role', 'listbox');\n        return div;\n    },\n    choiceGroup: function (_a, _b) {\n        var allowHTML = _a.allowHTML, _c = _a.classNames, group = _c.group, groupHeading = _c.groupHeading, itemDisabled = _c.itemDisabled;\n        var id = _b.id, label = _b.label, disabled = _b.disabled;\n        var rawLabel = unwrapStringForRaw(label);\n        var div = document.createElement('div');\n        addClassesToElement(div, group);\n        if (disabled) {\n            addClassesToElement(div, itemDisabled);\n        }\n        div.setAttribute('role', 'group');\n        div.dataset.group = '';\n        div.dataset.id = id;\n        div.dataset.value = rawLabel;\n        if (disabled) {\n            div.setAttribute('aria-disabled', 'true');\n        }\n        var heading = document.createElement('div');\n        addClassesToElement(heading, groupHeading);\n        setElementHtml(heading, allowHTML, label || '');\n        div.appendChild(heading);\n        return div;\n    },\n    choice: function (_a, choice, selectText, groupName) {\n        var allowHTML = _a.allowHTML, _b = _a.classNames, item = _b.item, itemChoice = _b.itemChoice, itemSelectable = _b.itemSelectable, selectedState = _b.selectedState, itemDisabled = _b.itemDisabled, description = _b.description, placeholder = _b.placeholder;\n        // eslint-disable-next-line prefer-destructuring\n        var label = choice.label;\n        var rawValue = unwrapStringForRaw(choice.value);\n        var div = document.createElement('div');\n        div.id = choice.elementId;\n        addClassesToElement(div, item);\n        addClassesToElement(div, itemChoice);\n        if (groupName && typeof label === 'string') {\n            label = escapeForTemplate(allowHTML, label);\n            label += \" (\".concat(groupName, \")\");\n            label = { trusted: label };\n        }\n        var describedBy = div;\n        if (choice.labelClass) {\n            var spanLabel = document.createElement('span');\n            setElementHtml(spanLabel, allowHTML, label);\n            addClassesToElement(spanLabel, choice.labelClass);\n            describedBy = spanLabel;\n            div.appendChild(spanLabel);\n        }\n        else {\n            setElementHtml(div, allowHTML, label);\n        }\n        if (choice.labelDescription) {\n            var descId = \"\".concat(choice.elementId, \"-description\");\n            describedBy.setAttribute('aria-describedby', descId);\n            var spanDesc = document.createElement('span');\n            setElementHtml(spanDesc, allowHTML, choice.labelDescription);\n            spanDesc.id = descId;\n            addClassesToElement(spanDesc, description);\n            div.appendChild(spanDesc);\n        }\n        if (choice.selected) {\n            addClassesToElement(div, selectedState);\n        }\n        if (choice.placeholder) {\n            addClassesToElement(div, placeholder);\n        }\n        div.setAttribute('role', choice.group ? 'treeitem' : 'option');\n        div.dataset.choice = '';\n        div.dataset.id = choice.id;\n        div.dataset.value = rawValue;\n        if (selectText) {\n            div.dataset.selectText = selectText;\n        }\n        if (choice.group) {\n            div.dataset.groupId = \"\".concat(choice.group.id);\n        }\n        assignCustomProperties(div, choice, false);\n        if (choice.disabled) {\n            addClassesToElement(div, itemDisabled);\n            div.dataset.choiceDisabled = '';\n            div.setAttribute('aria-disabled', 'true');\n        }\n        else {\n            addClassesToElement(div, itemSelectable);\n            div.dataset.choiceSelectable = '';\n            div.setAttribute('aria-selected', choice.selected ? 'true' : 'false');\n        }\n        return div;\n    },\n    input: function (_a, placeholderValue) {\n        var _b = _a.classNames, input = _b.input, inputCloned = _b.inputCloned, labelId = _a.labelId;\n        var inp = document.createElement('input');\n        inp.type = 'search';\n        addClassesToElement(inp, input);\n        addClassesToElement(inp, inputCloned);\n        inp.autocomplete = 'off';\n        inp.autocapitalize = 'off';\n        inp.spellcheck = false;\n        inp.setAttribute('aria-autocomplete', 'list');\n        if (placeholderValue) {\n            inp.setAttribute('aria-label', placeholderValue);\n        }\n        else if (!labelId) {\n            addAriaLabel(this._docRoot, this.passedElement.element.id, inp);\n        }\n        return inp;\n    },\n    dropdown: function (_a) {\n        var _b = _a.classNames, list = _b.list, listDropdown = _b.listDropdown;\n        var div = document.createElement('div');\n        addClassesToElement(div, list);\n        addClassesToElement(div, listDropdown);\n        div.setAttribute('aria-expanded', 'false');\n        return div;\n    },\n    notice: function (_a, innerHTML, type) {\n        var _b = _a.classNames, item = _b.item, itemChoice = _b.itemChoice, addChoice = _b.addChoice, noResults = _b.noResults, noChoices = _b.noChoices, noticeItem = _b.notice;\n        if (type === void 0) { type = NoticeTypes.generic; }\n        var notice = document.createElement('div');\n        setElementHtml(notice, true, innerHTML);\n        addClassesToElement(notice, item);\n        addClassesToElement(notice, itemChoice);\n        addClassesToElement(notice, noticeItem);\n        // eslint-disable-next-line default-case\n        switch (type) {\n            case NoticeTypes.addChoice:\n                addClassesToElement(notice, addChoice);\n                break;\n            case NoticeTypes.noResults:\n                addClassesToElement(notice, noResults);\n                break;\n            case NoticeTypes.noChoices:\n                addClassesToElement(notice, noChoices);\n                break;\n        }\n        if (type === NoticeTypes.addChoice) {\n            notice.dataset.choiceSelectable = '';\n            notice.dataset.choice = '';\n        }\n        return notice;\n    },\n    option: function (choice) {\n        // HtmlOptionElement's label value does not support HTML, so the avoid double escaping unwrap the untrusted string.\n        var labelValue = unwrapStringForRaw(choice.label);\n        var opt = new Option(labelValue, choice.value, false, choice.selected);\n        assignCustomProperties(opt, choice, true);\n        opt.disabled = choice.disabled;\n        if (choice.selected) {\n            opt.setAttribute('selected', '');\n        }\n        return opt;\n    },\n};\n\n/** @see {@link http://browserhacks.com/#hack-acea075d0ac6954f275a70023906050c} */\nvar IS_IE11 = '-ms-scroll-limit' in document.documentElement.style &&\n    '-ms-ime-align' in document.documentElement.style;\nvar USER_DEFAULTS = {};\nvar parseDataSetId = function (element) {\n    if (!element) {\n        return undefined;\n    }\n    return element.dataset.id ? parseInt(element.dataset.id, 10) : undefined;\n};\nvar selectableChoiceIdentifier = '[data-choice-selectable]';\n/**\n * Choices\n * @author Josh Johnson<josh@joshuajohnson.co.uk>\n */\nvar Choices = /** @class */ (function () {\n    function Choices(element, userConfig) {\n        if (element === void 0) { element = '[data-choice]'; }\n        if (userConfig === void 0) { userConfig = {}; }\n        var _this = this;\n        this.initialisedOK = undefined;\n        this._hasNonChoicePlaceholder = false;\n        this._lastAddedChoiceId = 0;\n        this._lastAddedGroupId = 0;\n        var defaults = Choices.defaults;\n        this.config = __assign(__assign(__assign({}, defaults.allOptions), defaults.options), userConfig);\n        ObjectsInConfig.forEach(function (key) {\n            _this.config[key] = __assign(__assign(__assign({}, defaults.allOptions[key]), defaults.options[key]), userConfig[key]);\n        });\n        var config = this.config;\n        if (!config.silent) {\n            this._validateConfig();\n        }\n        var docRoot = config.shadowRoot || document.documentElement;\n        this._docRoot = docRoot;\n        var passedElement = typeof element === 'string' ? docRoot.querySelector(element) : element;\n        if (!passedElement ||\n            typeof passedElement !== 'object' ||\n            !(isHtmlInputElement(passedElement) || isHtmlSelectElement(passedElement))) {\n            if (!passedElement && typeof element === 'string') {\n                throw TypeError(\"Selector \".concat(element, \" failed to find an element\"));\n            }\n            throw TypeError(\"Expected one of the following types text|select-one|select-multiple\");\n        }\n        var elementType = passedElement.type;\n        var isText = elementType === PassedElementTypes.Text;\n        if (isText || config.maxItemCount !== 1) {\n            config.singleModeForMultiSelect = false;\n        }\n        if (config.singleModeForMultiSelect) {\n            elementType = PassedElementTypes.SelectMultiple;\n        }\n        var isSelectOne = elementType === PassedElementTypes.SelectOne;\n        var isSelectMultiple = elementType === PassedElementTypes.SelectMultiple;\n        var isSelect = isSelectOne || isSelectMultiple;\n        this._elementType = elementType;\n        this._isTextElement = isText;\n        this._isSelectOneElement = isSelectOne;\n        this._isSelectMultipleElement = isSelectMultiple;\n        this._isSelectElement = isSelectOne || isSelectMultiple;\n        this._canAddUserChoices = (isText && config.addItems) || (isSelect && config.addChoices);\n        if (typeof config.renderSelectedChoices !== 'boolean') {\n            config.renderSelectedChoices = config.renderSelectedChoices === 'always' || isSelectOne;\n        }\n        if (config.closeDropdownOnSelect === 'auto') {\n            config.closeDropdownOnSelect = isText || isSelectOne || config.singleModeForMultiSelect;\n        }\n        else {\n            config.closeDropdownOnSelect = coerceBool(config.closeDropdownOnSelect);\n        }\n        if (config.placeholder) {\n            if (config.placeholderValue) {\n                this._hasNonChoicePlaceholder = true;\n            }\n            else if (passedElement.dataset.placeholder) {\n                this._hasNonChoicePlaceholder = true;\n                config.placeholderValue = passedElement.dataset.placeholder;\n            }\n        }\n        if (userConfig.addItemFilter && typeof userConfig.addItemFilter !== 'function') {\n            var re = userConfig.addItemFilter instanceof RegExp ? userConfig.addItemFilter : new RegExp(userConfig.addItemFilter);\n            config.addItemFilter = re.test.bind(re);\n        }\n        if (this._isTextElement) {\n            this.passedElement = new WrappedInput({\n                element: passedElement,\n                classNames: config.classNames,\n            });\n        }\n        else {\n            var selectEl = passedElement;\n            this.passedElement = new WrappedSelect({\n                element: selectEl,\n                classNames: config.classNames,\n                template: function (data) { return _this._templates.option(data); },\n                extractPlaceholder: config.placeholder && !this._hasNonChoicePlaceholder,\n            });\n        }\n        this.initialised = false;\n        this._store = new Store(config);\n        this._currentValue = '';\n        config.searchEnabled = !isText && config.searchEnabled;\n        this._canSearch = config.searchEnabled;\n        this._isScrollingOnIe = false;\n        this._highlightPosition = 0;\n        this._wasTap = true;\n        this._placeholderValue = this._generatePlaceholderValue();\n        this._baseId = generateId(passedElement, 'choices-');\n        /**\n         * setting direction in cases where it's explicitly set on passedElement\n         * or when calculated direction is different from the document\n         */\n        this._direction = passedElement.dir;\n        if (!this._direction) {\n            var elementDirection = window.getComputedStyle(passedElement).direction;\n            var documentDirection = window.getComputedStyle(document.documentElement).direction;\n            if (elementDirection !== documentDirection) {\n                this._direction = elementDirection;\n            }\n        }\n        this._idNames = {\n            itemChoice: 'item-choice',\n        };\n        this._templates = defaults.templates;\n        this._render = this._render.bind(this);\n        this._onFocus = this._onFocus.bind(this);\n        this._onBlur = this._onBlur.bind(this);\n        this._onKeyUp = this._onKeyUp.bind(this);\n        this._onKeyDown = this._onKeyDown.bind(this);\n        this._onInput = this._onInput.bind(this);\n        this._onClick = this._onClick.bind(this);\n        this._onTouchMove = this._onTouchMove.bind(this);\n        this._onTouchEnd = this._onTouchEnd.bind(this);\n        this._onMouseDown = this._onMouseDown.bind(this);\n        this._onMouseOver = this._onMouseOver.bind(this);\n        this._onFormReset = this._onFormReset.bind(this);\n        this._onSelectKey = this._onSelectKey.bind(this);\n        this._onEnterKey = this._onEnterKey.bind(this);\n        this._onEscapeKey = this._onEscapeKey.bind(this);\n        this._onDirectionKey = this._onDirectionKey.bind(this);\n        this._onDeleteKey = this._onDeleteKey.bind(this);\n        this._onChange = this._onChange.bind(this);\n        this._onInvalid = this._onInvalid.bind(this);\n        // If element has already been initialised with Choices, fail silently\n        if (this.passedElement.isActive) {\n            if (!config.silent) {\n                console.warn('Trying to initialise Choices on element already initialised', { element: element });\n            }\n            this.initialised = true;\n            this.initialisedOK = false;\n            return;\n        }\n        // Let's go\n        this.init();\n        // preserve the selected item list after setup for form reset\n        this._initialItems = this._store.items.map(function (choice) { return choice.value; });\n    }\n    Object.defineProperty(Choices, \"defaults\", {\n        get: function () {\n            return Object.preventExtensions({\n                get options() {\n                    return USER_DEFAULTS;\n                },\n                get allOptions() {\n                    return DEFAULT_CONFIG;\n                },\n                get templates() {\n                    return templates;\n                },\n            });\n        },\n        enumerable: false,\n        configurable: true\n    });\n    Choices.prototype.init = function () {\n        if (this.initialised || this.initialisedOK !== undefined) {\n            return;\n        }\n        this._searcher = getSearcher(this.config);\n        this._loadChoices();\n        this._createTemplates();\n        this._createElements();\n        this._createStructure();\n        if ((this._isTextElement && !this.config.addItems) ||\n            this.passedElement.element.hasAttribute('disabled') ||\n            !!this.passedElement.element.closest('fieldset:disabled')) {\n            this.disable();\n        }\n        else {\n            this.enable();\n            this._addEventListeners();\n        }\n        // should be triggered **after** disabled state to avoid additional re-draws\n        this._initStore();\n        this.initialised = true;\n        this.initialisedOK = true;\n        var callbackOnInit = this.config.callbackOnInit;\n        // Run callback if it is a function\n        if (typeof callbackOnInit === 'function') {\n            callbackOnInit.call(this);\n        }\n    };\n    Choices.prototype.destroy = function () {\n        if (!this.initialised) {\n            return;\n        }\n        this._removeEventListeners();\n        this.passedElement.reveal();\n        this.containerOuter.unwrap(this.passedElement.element);\n        this._store._listeners = []; // prevents select/input value being wiped\n        this.clearStore(false);\n        this._stopSearch();\n        this._templates = Choices.defaults.templates;\n        this.initialised = false;\n        this.initialisedOK = undefined;\n    };\n    Choices.prototype.enable = function () {\n        if (this.passedElement.isDisabled) {\n            this.passedElement.enable();\n        }\n        if (this.containerOuter.isDisabled) {\n            this._addEventListeners();\n            this.input.enable();\n            this.containerOuter.enable();\n        }\n        return this;\n    };\n    Choices.prototype.disable = function () {\n        if (!this.passedElement.isDisabled) {\n            this.passedElement.disable();\n        }\n        if (!this.containerOuter.isDisabled) {\n            this._removeEventListeners();\n            this.input.disable();\n            this.containerOuter.disable();\n        }\n        return this;\n    };\n    Choices.prototype.highlightItem = function (item, runEvent) {\n        if (runEvent === void 0) { runEvent = true; }\n        if (!item || !item.id) {\n            return this;\n        }\n        var choice = this._store.items.find(function (c) { return c.id === item.id; });\n        if (!choice || choice.highlighted) {\n            return this;\n        }\n        this._store.dispatch(highlightItem(choice, true));\n        if (runEvent) {\n            this.passedElement.triggerEvent(EventType.highlightItem, getChoiceForOutput(choice));\n        }\n        return this;\n    };\n    Choices.prototype.unhighlightItem = function (item, runEvent) {\n        if (runEvent === void 0) { runEvent = true; }\n        if (!item || !item.id) {\n            return this;\n        }\n        var choice = this._store.items.find(function (c) { return c.id === item.id; });\n        if (!choice || !choice.highlighted) {\n            return this;\n        }\n        this._store.dispatch(highlightItem(choice, false));\n        if (runEvent) {\n            this.passedElement.triggerEvent(EventType.unhighlightItem, getChoiceForOutput(choice));\n        }\n        return this;\n    };\n    Choices.prototype.highlightAll = function () {\n        var _this = this;\n        this._store.withTxn(function () {\n            _this._store.items.forEach(function (item) {\n                if (!item.highlighted) {\n                    _this._store.dispatch(highlightItem(item, true));\n                    _this.passedElement.triggerEvent(EventType.highlightItem, getChoiceForOutput(item));\n                }\n            });\n        });\n        return this;\n    };\n    Choices.prototype.unhighlightAll = function () {\n        var _this = this;\n        this._store.withTxn(function () {\n            _this._store.items.forEach(function (item) {\n                if (item.highlighted) {\n                    _this._store.dispatch(highlightItem(item, false));\n                    _this.passedElement.triggerEvent(EventType.highlightItem, getChoiceForOutput(item));\n                }\n            });\n        });\n        return this;\n    };\n    Choices.prototype.removeActiveItemsByValue = function (value) {\n        var _this = this;\n        this._store.withTxn(function () {\n            _this._store.items.filter(function (item) { return item.value === value; }).forEach(function (item) { return _this._removeItem(item); });\n        });\n        return this;\n    };\n    Choices.prototype.removeActiveItems = function (excludedId) {\n        var _this = this;\n        this._store.withTxn(function () {\n            _this._store.items.filter(function (_a) {\n                var id = _a.id;\n                return id !== excludedId;\n            }).forEach(function (item) { return _this._removeItem(item); });\n        });\n        return this;\n    };\n    Choices.prototype.removeHighlightedItems = function (runEvent) {\n        var _this = this;\n        if (runEvent === void 0) { runEvent = false; }\n        this._store.withTxn(function () {\n            _this._store.highlightedActiveItems.forEach(function (item) {\n                _this._removeItem(item);\n                // If this action was performed by the user\n                // trigger the event\n                if (runEvent) {\n                    _this._triggerChange(item.value);\n                }\n            });\n        });\n        return this;\n    };\n    Choices.prototype.showDropdown = function (preventInputFocus) {\n        var _this = this;\n        if (this.dropdown.isActive) {\n            return this;\n        }\n        if (preventInputFocus === undefined) {\n            // eslint-disable-next-line no-param-reassign\n            preventInputFocus = !this._canSearch;\n        }\n        requestAnimationFrame(function () {\n            _this.dropdown.show();\n            var rect = _this.dropdown.element.getBoundingClientRect();\n            _this.containerOuter.open(rect.bottom, rect.height);\n            if (!preventInputFocus) {\n                _this.input.focus();\n            }\n            _this.passedElement.triggerEvent(EventType.showDropdown);\n            var activeElement = _this.choiceList.element.querySelector(getClassNamesSelector(_this.config.classNames.selectedState));\n            if (activeElement !== null && !isScrolledIntoView(activeElement, _this.choiceList.element)) {\n                // We use the native scrollIntoView function instead of choiceList.scrollToChildElement to avoid animated scroll.\n                activeElement.scrollIntoView();\n            }\n        });\n        return this;\n    };\n    Choices.prototype.hideDropdown = function (preventInputBlur) {\n        var _this = this;\n        if (!this.dropdown.isActive) {\n            return this;\n        }\n        this._removeHighlightedChoices();\n        requestAnimationFrame(function () {\n            _this.dropdown.hide();\n            _this.containerOuter.close();\n            if (!preventInputBlur && _this._canSearch) {\n                _this.input.removeActiveDescendant();\n                _this.input.blur();\n            }\n            _this.passedElement.triggerEvent(EventType.hideDropdown);\n        });\n        return this;\n    };\n    Choices.prototype.getValue = function (valueOnly) {\n        var values = this._store.items.map(function (item) {\n            return (valueOnly ? item.value : getChoiceForOutput(item));\n        });\n        return this._isSelectOneElement || this.config.singleModeForMultiSelect ? values[0] : values;\n    };\n    Choices.prototype.setValue = function (items) {\n        var _this = this;\n        if (!this.initialisedOK) {\n            this._warnChoicesInitFailed('setValue');\n            return this;\n        }\n        this._store.withTxn(function () {\n            items.forEach(function (value) {\n                if (value) {\n                    _this._addChoice(mapInputToChoice(value, false));\n                }\n            });\n        });\n        // @todo integrate with Store\n        this._searcher.reset();\n        return this;\n    };\n    Choices.prototype.setChoiceByValue = function (value) {\n        var _this = this;\n        if (!this.initialisedOK) {\n            this._warnChoicesInitFailed('setChoiceByValue');\n            return this;\n        }\n        if (this._isTextElement) {\n            return this;\n        }\n        this._store.withTxn(function () {\n            // If only one value has been passed, convert to array\n            var choiceValue = Array.isArray(value) ? value : [value];\n            // Loop through each value and\n            choiceValue.forEach(function (val) { return _this._findAndSelectChoiceByValue(val); });\n            _this.unhighlightAll();\n        });\n        // @todo integrate with Store\n        this._searcher.reset();\n        return this;\n    };\n    /**\n     * Set choices of select input via an array of objects (or function that returns array of object or promise of it),\n     * a value field name and a label field name.\n     * This behaves the same as passing items via the choices option but can be called after initialising Choices.\n     * This can also be used to add groups of choices (see example 2); Optionally pass a true `replaceChoices` value to remove any existing choices.\n     * Optionally pass a `customProperties` object to add additional data to your choices (useful when searching/filtering etc).\n     *\n     * **Input types affected:** select-one, select-multiple\n     *\n     * @example\n     * ```js\n     * const example = new Choices(element);\n     *\n     * example.setChoices([\n     *   {value: 'One', label: 'Label One', disabled: true},\n     *   {value: 'Two', label: 'Label Two', selected: true},\n     *   {value: 'Three', label: 'Label Three'},\n     * ], 'value', 'label', false);\n     * ```\n     *\n     * @example\n     * ```js\n     * const example = new Choices(element);\n     *\n     * example.setChoices(async () => {\n     *   try {\n     *      const items = await fetch('/items');\n     *      return items.json()\n     *   } catch(err) {\n     *      console.error(err)\n     *   }\n     * });\n     * ```\n     *\n     * @example\n     * ```js\n     * const example = new Choices(element);\n     *\n     * example.setChoices([{\n     *   label: 'Group one',\n     *   id: 1,\n     *   disabled: false,\n     *   choices: [\n     *     {value: 'Child One', label: 'Child One', selected: true},\n     *     {value: 'Child Two', label: 'Child Two',  disabled: true},\n     *     {value: 'Child Three', label: 'Child Three'},\n     *   ]\n     * },\n     * {\n     *   label: 'Group two',\n     *   id: 2,\n     *   disabled: false,\n     *   choices: [\n     *     {value: 'Child Four', label: 'Child Four', disabled: true},\n     *     {value: 'Child Five', label: 'Child Five'},\n     *     {value: 'Child Six', label: 'Child Six', customProperties: {\n     *       description: 'Custom description about child six',\n     *       random: 'Another random custom property'\n     *     }},\n     *   ]\n     * }], 'value', 'label', false);\n     * ```\n     */\n    Choices.prototype.setChoices = function (choicesArrayOrFetcher, value, label, replaceChoices, clearSearchFlag, replaceItems) {\n        var _this = this;\n        if (choicesArrayOrFetcher === void 0) { choicesArrayOrFetcher = []; }\n        if (value === void 0) { value = 'value'; }\n        if (label === void 0) { label = 'label'; }\n        if (replaceChoices === void 0) { replaceChoices = false; }\n        if (clearSearchFlag === void 0) { clearSearchFlag = true; }\n        if (replaceItems === void 0) { replaceItems = false; }\n        if (!this.initialisedOK) {\n            this._warnChoicesInitFailed('setChoices');\n            return this;\n        }\n        if (!this._isSelectElement) {\n            throw new TypeError(\"setChoices can't be used with INPUT based Choices\");\n        }\n        if (typeof value !== 'string' || !value) {\n            throw new TypeError(\"value parameter must be a name of 'value' field in passed objects\");\n        }\n        if (typeof choicesArrayOrFetcher === 'function') {\n            // it's a choices fetcher function\n            var fetcher_1 = choicesArrayOrFetcher(this);\n            if (typeof Promise === 'function' && fetcher_1 instanceof Promise) {\n                // that's a promise\n                // eslint-disable-next-line no-promise-executor-return\n                return new Promise(function (resolve) { return requestAnimationFrame(resolve); })\n                    .then(function () { return _this._handleLoadingState(true); })\n                    .then(function () { return fetcher_1; })\n                    .then(function (data) {\n                    return _this.setChoices(data, value, label, replaceChoices, clearSearchFlag, replaceItems);\n                })\n                    .catch(function (err) {\n                    if (!_this.config.silent) {\n                        console.error(err);\n                    }\n                })\n                    .then(function () { return _this._handleLoadingState(false); })\n                    .then(function () { return _this; });\n            }\n            // function returned something else than promise, let's check if it's an array of choices\n            if (!Array.isArray(fetcher_1)) {\n                throw new TypeError(\".setChoices first argument function must return either array of choices or Promise, got: \".concat(typeof fetcher_1));\n            }\n            // recursion with results, it's sync and choices were cleared already\n            return this.setChoices(fetcher_1, value, label, false);\n        }\n        if (!Array.isArray(choicesArrayOrFetcher)) {\n            throw new TypeError(\".setChoices must be called either with array of choices with a function resulting into Promise of array of choices\");\n        }\n        this.containerOuter.removeLoadingState();\n        this._store.withTxn(function () {\n            if (clearSearchFlag) {\n                _this._isSearching = false;\n            }\n            // Clear choices if needed\n            if (replaceChoices) {\n                _this.clearChoices(true, replaceItems);\n            }\n            var isDefaultValue = value === 'value';\n            var isDefaultLabel = label === 'label';\n            choicesArrayOrFetcher.forEach(function (groupOrChoice) {\n                if ('choices' in groupOrChoice) {\n                    var group = groupOrChoice;\n                    if (!isDefaultLabel) {\n                        group = __assign(__assign({}, group), { label: group[label] });\n                    }\n                    _this._addGroup(mapInputToChoice(group, true));\n                }\n                else {\n                    var choice = groupOrChoice;\n                    if (!isDefaultLabel || !isDefaultValue) {\n                        choice = __assign(__assign({}, choice), { value: choice[value], label: choice[label] });\n                    }\n                    var choiceFull = mapInputToChoice(choice, false);\n                    _this._addChoice(choiceFull);\n                    if (choiceFull.placeholder && !_this._hasNonChoicePlaceholder) {\n                        _this._placeholderValue = unwrapStringForEscaped(choiceFull.label);\n                    }\n                }\n            });\n            _this.unhighlightAll();\n        });\n        // @todo integrate with Store\n        this._searcher.reset();\n        return this;\n    };\n    Choices.prototype.refresh = function (withEvents, selectFirstOption, deselectAll) {\n        var _this = this;\n        if (withEvents === void 0) { withEvents = false; }\n        if (selectFirstOption === void 0) { selectFirstOption = false; }\n        if (deselectAll === void 0) { deselectAll = false; }\n        if (!this._isSelectElement) {\n            if (!this.config.silent) {\n                console.warn('refresh method can only be used on choices backed by a <select> element');\n            }\n            return this;\n        }\n        this._store.withTxn(function () {\n            var choicesFromOptions = _this.passedElement.optionsAsChoices();\n            // Build the list of items which require preserving\n            var existingItems = {};\n            if (!deselectAll) {\n                _this._store.items.forEach(function (choice) {\n                    if (choice.id && choice.active && choice.selected) {\n                        existingItems[choice.value] = true;\n                    }\n                });\n            }\n            _this.clearStore(false);\n            var updateChoice = function (choice) {\n                if (deselectAll) {\n                    _this._store.dispatch(removeItem$1(choice));\n                }\n                else if (existingItems[choice.value]) {\n                    choice.selected = true;\n                }\n            };\n            choicesFromOptions.forEach(function (groupOrChoice) {\n                if ('choices' in groupOrChoice) {\n                    groupOrChoice.choices.forEach(updateChoice);\n                    return;\n                }\n                updateChoice(groupOrChoice);\n            });\n            /* @todo only generate add events for the added options instead of all\n            if (withEvents) {\n              items.forEach((choice) => {\n                if (existingItems[choice.value]) {\n                  this.passedElement.triggerEvent(\n                    EventType.removeItem,\n                    this._getChoiceForEvent(choice),\n                  );\n                }\n              });\n            }\n            */\n            // load new choices & items\n            _this._addPredefinedChoices(choicesFromOptions, selectFirstOption, withEvents);\n            // re-do search if required\n            if (_this._isSearching) {\n                _this._searchChoices(_this.input.value);\n            }\n        });\n        return this;\n    };\n    Choices.prototype.removeChoice = function (value) {\n        var choice = this._store.choices.find(function (c) { return c.value === value; });\n        if (!choice) {\n            return this;\n        }\n        this._clearNotice();\n        this._store.dispatch(removeChoice(choice));\n        // @todo integrate with Store\n        this._searcher.reset();\n        if (choice.selected) {\n            this.passedElement.triggerEvent(EventType.removeItem, getChoiceForOutput(choice));\n        }\n        return this;\n    };\n    Choices.prototype.clearChoices = function (clearOptions, clearItems) {\n        var _this = this;\n        if (clearOptions === void 0) { clearOptions = true; }\n        if (clearItems === void 0) { clearItems = false; }\n        if (clearOptions) {\n            if (clearItems) {\n                this.passedElement.element.replaceChildren('');\n            }\n            else {\n                this.passedElement.element.querySelectorAll(':not([selected])').forEach(function (el) {\n                    el.remove();\n                });\n            }\n        }\n        this.itemList.element.replaceChildren('');\n        this.choiceList.element.replaceChildren('');\n        this._clearNotice();\n        this._store.withTxn(function () {\n            var items = clearItems ? [] : _this._store.items;\n            _this._store.reset();\n            items.forEach(function (item) {\n                _this._store.dispatch(addChoice(item));\n                _this._store.dispatch(addItem(item));\n            });\n        });\n        // @todo integrate with Store\n        this._searcher.reset();\n        return this;\n    };\n    Choices.prototype.clearStore = function (clearOptions) {\n        if (clearOptions === void 0) { clearOptions = true; }\n        this.clearChoices(clearOptions, true);\n        this._stopSearch();\n        this._lastAddedChoiceId = 0;\n        this._lastAddedGroupId = 0;\n        return this;\n    };\n    Choices.prototype.clearInput = function () {\n        var shouldSetInputWidth = !this._isSelectOneElement;\n        this.input.clear(shouldSetInputWidth);\n        this._stopSearch();\n        return this;\n    };\n    Choices.prototype._validateConfig = function () {\n        var config = this.config;\n        var invalidConfigOptions = diff(config, DEFAULT_CONFIG);\n        if (invalidConfigOptions.length) {\n            console.warn('Unknown config option(s) passed', invalidConfigOptions.join(', '));\n        }\n        if (config.allowHTML && config.allowHtmlUserInput) {\n            if (config.addItems) {\n                console.warn('Warning: allowHTML/allowHtmlUserInput/addItems all being true is strongly not recommended and may lead to XSS attacks');\n            }\n            if (config.addChoices) {\n                console.warn('Warning: allowHTML/allowHtmlUserInput/addChoices all being true is strongly not recommended and may lead to XSS attacks');\n            }\n        }\n    };\n    Choices.prototype._render = function (changes) {\n        if (changes === void 0) { changes = { choices: true, groups: true, items: true }; }\n        if (this._store.inTxn()) {\n            return;\n        }\n        if (this._isSelectElement) {\n            if (changes.choices || changes.groups) {\n                this._renderChoices();\n            }\n        }\n        if (changes.items) {\n            this._renderItems();\n        }\n    };\n    Choices.prototype._renderChoices = function () {\n        var _this = this;\n        if (!this._canAddItems()) {\n            return; // block rendering choices if the input limit is reached.\n        }\n        var _a = this, config = _a.config, isSearching = _a._isSearching;\n        var _b = this._store, activeGroups = _b.activeGroups, activeChoices = _b.activeChoices;\n        var renderLimit = isSearching ? config.searchResultLimit : config.renderChoiceLimit;\n        if (this._isSelectElement) {\n            var backingOptions = activeChoices.filter(function (choice) { return !choice.element; });\n            if (backingOptions.length) {\n                this.passedElement.addOptions(backingOptions);\n            }\n        }\n        var fragment = document.createDocumentFragment();\n        var renderableChoices = function (choices) {\n            return choices.filter(function (choice) {\n                return !choice.placeholder &&\n                    (isSearching\n                        ? (config.searchRenderSelectedChoices || !choice.selected) && !!choice.rank\n                        : config.renderSelectedChoices || !choice.selected);\n            });\n        };\n        var showLabel = config.appendGroupInSearch && isSearching;\n        var selectableChoices = false;\n        var highlightedEl = null;\n        var renderChoices = function (choices, withinGroup) {\n            if (isSearching) {\n                // sortByRank is used to ensure stable sorting, as scores are non-unique\n                // this additionally ensures fuseOptions.sortFn is not ignored\n                choices.sort(sortByRank);\n            }\n            else if (config.shouldSort) {\n                choices.sort(config.sorter);\n            }\n            var choiceLimit = choices.length;\n            choiceLimit = !withinGroup && renderLimit > 0 && choiceLimit > renderLimit ? renderLimit : choiceLimit;\n            choiceLimit--;\n            choices.every(function (choice, index) {\n                // choiceEl being empty signals the contents has probably significantly changed\n                var dropdownItem = choice.choiceEl ||\n                    _this._templates.choice(config, choice, config.itemSelectText, showLabel && choice.group ? choice.group.label : undefined);\n                choice.choiceEl = dropdownItem;\n                fragment.appendChild(dropdownItem);\n                if (isSearching || !choice.selected) {\n                    selectableChoices = true;\n                }\n                else if (!highlightedEl) {\n                    highlightedEl = dropdownItem;\n                }\n                return index < choiceLimit;\n            });\n        };\n        if (activeChoices.length) {\n            if (config.resetScrollPosition) {\n                requestAnimationFrame(function () { return _this.choiceList.scrollToTop(); });\n            }\n            if (!this._hasNonChoicePlaceholder && !isSearching && this._isSelectOneElement) {\n                // If we have a placeholder choice along with groups\n                renderChoices(activeChoices.filter(function (choice) { return choice.placeholder && !choice.group; }), false);\n            }\n            // If we have grouped options\n            if (activeGroups.length && !isSearching) {\n                if (config.shouldSort) {\n                    activeGroups.sort(config.sorter);\n                }\n                // render Choices without group first, regardless of sort, otherwise they won't be distinguishable\n                // from the last group\n                renderChoices(activeChoices.filter(function (choice) { return !choice.placeholder && !choice.group; }), false);\n                activeGroups.forEach(function (group) {\n                    var groupChoices = renderableChoices(group.choices);\n                    if (groupChoices.length) {\n                        if (group.label) {\n                            var dropdownGroup = group.groupEl || _this._templates.choiceGroup(_this.config, group);\n                            group.groupEl = dropdownGroup;\n                            dropdownGroup.remove();\n                            fragment.appendChild(dropdownGroup);\n                        }\n                        renderChoices(groupChoices, true);\n                    }\n                });\n            }\n            else {\n                renderChoices(renderableChoices(activeChoices), false);\n            }\n        }\n        if (!selectableChoices && (isSearching || !fragment.children.length || !config.renderSelectedChoices)) {\n            if (!this._notice) {\n                this._notice = {\n                    text: resolveStringFunction(isSearching ? config.noResultsText : config.noChoicesText),\n                    type: isSearching ? NoticeTypes.noResults : NoticeTypes.noChoices,\n                };\n            }\n            fragment.replaceChildren('');\n        }\n        this._renderNotice(fragment);\n        this.choiceList.element.replaceChildren(fragment);\n        this._highlightChoice(highlightedEl);\n    };\n    Choices.prototype._renderItems = function () {\n        var _this = this;\n        var items = this._store.items || [];\n        var itemList = this.itemList.element;\n        var config = this.config;\n        var fragment = document.createDocumentFragment();\n        var itemFromList = function (item) {\n            return itemList.querySelector(\"[data-item][data-id=\\\"\".concat(item.id, \"\\\"]\"));\n        };\n        var addItemToFragment = function (item) {\n            var el = item.itemEl;\n            if (el && el.parentElement) {\n                return;\n            }\n            el = itemFromList(item) || _this._templates.item(config, item, config.removeItemButton);\n            item.itemEl = el;\n            fragment.appendChild(el);\n        };\n        // new items\n        items.forEach(addItemToFragment);\n        var addedItems = !!fragment.childNodes.length;\n        if (this._isSelectOneElement) {\n            var existingItems = itemList.children.length;\n            if (addedItems || existingItems > 1) {\n                var placeholder = itemList.querySelector(getClassNamesSelector(config.classNames.placeholder));\n                if (placeholder) {\n                    placeholder.remove();\n                }\n            }\n            else if (!addedItems && !existingItems && this._placeholderValue) {\n                addedItems = true;\n                addItemToFragment(mapInputToChoice({\n                    selected: true,\n                    value: '',\n                    label: this._placeholderValue,\n                    placeholder: true,\n                }, false));\n            }\n        }\n        if (addedItems) {\n            itemList.append(fragment);\n            if (config.shouldSortItems && !this._isSelectOneElement) {\n                items.sort(config.sorter);\n                // push sorting into the DOM\n                items.forEach(function (item) {\n                    var el = itemFromList(item);\n                    if (el) {\n                        el.remove();\n                        fragment.append(el);\n                    }\n                });\n                itemList.append(fragment);\n            }\n        }\n        if (this._isTextElement) {\n            // Update the value of the hidden input\n            this.passedElement.value = items.map(function (_a) {\n                var value = _a.value;\n                return value;\n            }).join(config.delimiter);\n        }\n    };\n    Choices.prototype._displayNotice = function (text, type, openDropdown) {\n        if (openDropdown === void 0) { openDropdown = true; }\n        var oldNotice = this._notice;\n        if (oldNotice &&\n            ((oldNotice.type === type && oldNotice.text === text) ||\n                (oldNotice.type === NoticeTypes.addChoice &&\n                    (type === NoticeTypes.noResults || type === NoticeTypes.noChoices)))) {\n            if (openDropdown) {\n                this.showDropdown(true);\n            }\n            return;\n        }\n        this._clearNotice();\n        this._notice = text\n            ? {\n                text: text,\n                type: type,\n            }\n            : undefined;\n        this._renderNotice();\n        if (openDropdown && text) {\n            this.showDropdown(true);\n        }\n    };\n    Choices.prototype._clearNotice = function () {\n        if (!this._notice) {\n            return;\n        }\n        var noticeElement = this.choiceList.element.querySelector(getClassNamesSelector(this.config.classNames.notice));\n        if (noticeElement) {\n            noticeElement.remove();\n        }\n        this._notice = undefined;\n    };\n    Choices.prototype._renderNotice = function (fragment) {\n        var noticeConf = this._notice;\n        if (noticeConf) {\n            var notice = this._templates.notice(this.config, noticeConf.text, noticeConf.type);\n            if (fragment) {\n                fragment.append(notice);\n            }\n            else {\n                this.choiceList.prepend(notice);\n            }\n        }\n    };\n    /**\n     * @deprecated Use utils.getChoiceForOutput\n     */\n    // eslint-disable-next-line class-methods-use-this\n    Choices.prototype._getChoiceForOutput = function (choice, keyCode) {\n        return getChoiceForOutput(choice, keyCode);\n    };\n    Choices.prototype._triggerChange = function (value) {\n        if (value === undefined || value === null) {\n            return;\n        }\n        this.passedElement.triggerEvent(EventType.change, {\n            value: value,\n        });\n    };\n    Choices.prototype._handleButtonAction = function (element) {\n        var _this = this;\n        var items = this._store.items;\n        if (!items.length || !this.config.removeItems || !this.config.removeItemButton) {\n            return;\n        }\n        var id = element && parseDataSetId(element.closest('[data-id]'));\n        var itemToRemove = id && items.find(function (item) { return item.id === id; });\n        if (!itemToRemove) {\n            return;\n        }\n        this._store.withTxn(function () {\n            // Remove item associated with button\n            _this._removeItem(itemToRemove);\n            _this._triggerChange(itemToRemove.value);\n            if (_this._isSelectOneElement && !_this._hasNonChoicePlaceholder) {\n                var placeholderChoice = (_this.config.shouldSort ? _this._store.choices.reverse() : _this._store.choices).find(function (choice) { return choice.placeholder; });\n                if (placeholderChoice) {\n                    _this._addItem(placeholderChoice);\n                    _this.unhighlightAll();\n                    if (placeholderChoice.value) {\n                        _this._triggerChange(placeholderChoice.value);\n                    }\n                }\n            }\n        });\n    };\n    Choices.prototype._handleItemAction = function (element, hasShiftKey) {\n        var _this = this;\n        if (hasShiftKey === void 0) { hasShiftKey = false; }\n        var items = this._store.items;\n        if (!items.length || !this.config.removeItems || this._isSelectOneElement) {\n            return;\n        }\n        var id = parseDataSetId(element);\n        if (!id) {\n            return;\n        }\n        // We only want to select one item with a click\n        // so we deselect any items that aren't the target\n        // unless shift is being pressed\n        items.forEach(function (item) {\n            if (item.id === id && !item.highlighted) {\n                _this.highlightItem(item);\n            }\n            else if (!hasShiftKey && item.highlighted) {\n                _this.unhighlightItem(item);\n            }\n        });\n        // Focus input as without focus, a user cannot do anything with a\n        // highlighted item\n        this.input.focus();\n    };\n    Choices.prototype._handleChoiceAction = function (element) {\n        var _this = this;\n        // If we are clicking on an option\n        var id = parseDataSetId(element);\n        var choice = id && this._store.getChoiceById(id);\n        if (!choice || choice.disabled) {\n            return false;\n        }\n        var hasActiveDropdown = this.dropdown.isActive;\n        if (!choice.selected) {\n            if (!this._canAddItems()) {\n                return true; // causes _onEnterKey to early out\n            }\n            this._store.withTxn(function () {\n                _this._addItem(choice, true, true);\n                _this.clearInput();\n                _this.unhighlightAll();\n            });\n            this._triggerChange(choice.value);\n        }\n        // We want to close the dropdown if we are dealing with a single select box\n        if (hasActiveDropdown && this.config.closeDropdownOnSelect) {\n            this.hideDropdown(true);\n            this.containerOuter.element.focus();\n        }\n        return true;\n    };\n    Choices.prototype._handleBackspace = function (items) {\n        var config = this.config;\n        if (!config.removeItems || !items.length) {\n            return;\n        }\n        var lastItem = items[items.length - 1];\n        var hasHighlightedItems = items.some(function (item) { return item.highlighted; });\n        // If editing the last item is allowed and there are not other selected items,\n        // we can edit the item value. Otherwise if we can remove items, remove all selected items\n        if (config.editItems && !hasHighlightedItems && lastItem) {\n            this.input.value = lastItem.value;\n            this.input.setWidth();\n            this._removeItem(lastItem);\n            this._triggerChange(lastItem.value);\n        }\n        else {\n            if (!hasHighlightedItems) {\n                // Highlight last item if none already highlighted\n                this.highlightItem(lastItem, false);\n            }\n            this.removeHighlightedItems(true);\n        }\n    };\n    Choices.prototype._loadChoices = function () {\n        var _a;\n        var _this = this;\n        var config = this.config;\n        if (this._isTextElement) {\n            // Assign preset items from passed object first\n            this._presetChoices = config.items.map(function (e) { return mapInputToChoice(e, false); });\n            // Add any values passed from attribute\n            if (this.passedElement.value) {\n                var elementItems = this.passedElement.value\n                    .split(config.delimiter)\n                    .map(function (e) { return mapInputToChoice(e, false, _this.config.allowHtmlUserInput); });\n                this._presetChoices = this._presetChoices.concat(elementItems);\n            }\n            this._presetChoices.forEach(function (choice) {\n                choice.selected = true;\n            });\n        }\n        else if (this._isSelectElement) {\n            // Assign preset choices from passed object\n            this._presetChoices = config.choices.map(function (e) { return mapInputToChoice(e, true); });\n            // Create array of choices from option elements\n            var choicesFromOptions = this.passedElement.optionsAsChoices();\n            if (choicesFromOptions) {\n                (_a = this._presetChoices).push.apply(_a, choicesFromOptions);\n            }\n        }\n    };\n    Choices.prototype._handleLoadingState = function (setLoading) {\n        if (setLoading === void 0) { setLoading = true; }\n        var el = this.itemList.element;\n        if (setLoading) {\n            this.disable();\n            this.containerOuter.addLoadingState();\n            if (this._isSelectOneElement) {\n                el.replaceChildren(this._templates.placeholder(this.config, this.config.loadingText));\n            }\n            else {\n                this.input.placeholder = this.config.loadingText;\n            }\n        }\n        else {\n            this.enable();\n            this.containerOuter.removeLoadingState();\n            if (this._isSelectOneElement) {\n                el.replaceChildren('');\n                this._render();\n            }\n            else {\n                this.input.placeholder = this._placeholderValue || '';\n            }\n        }\n    };\n    Choices.prototype._handleSearch = function (value) {\n        if (!this.input.isFocussed) {\n            return;\n        }\n        // Check that we have a value to search and the input was an alphanumeric character\n        if (value !== null && typeof value !== 'undefined' && value.length >= this.config.searchFloor) {\n            var resultCount = this.config.searchChoices ? this._searchChoices(value) : 0;\n            if (resultCount !== null) {\n                // Trigger search event\n                this.passedElement.triggerEvent(EventType.search, {\n                    value: value,\n                    resultCount: resultCount,\n                });\n            }\n        }\n        else if (this._store.choices.some(function (option) { return !option.active; })) {\n            this._stopSearch();\n        }\n    };\n    Choices.prototype._canAddItems = function () {\n        var config = this.config;\n        var maxItemCount = config.maxItemCount, maxItemText = config.maxItemText;\n        if (!config.singleModeForMultiSelect && maxItemCount > 0 && maxItemCount <= this._store.items.length) {\n            this.choiceList.element.replaceChildren('');\n            this._notice = undefined;\n            this._displayNotice(typeof maxItemText === 'function' ? maxItemText(maxItemCount) : maxItemText, NoticeTypes.addChoice);\n            return false;\n        }\n        if (this._notice && this._notice.type === NoticeTypes.addChoice) {\n            this._clearNotice();\n        }\n        return true;\n    };\n    Choices.prototype._canCreateItem = function (value) {\n        var config = this.config;\n        var canAddItem = true;\n        var notice = '';\n        if (canAddItem && typeof config.addItemFilter === 'function' && !config.addItemFilter(value)) {\n            canAddItem = false;\n            notice = resolveNoticeFunction(config.customAddItemText, value, undefined);\n        }\n        if (canAddItem) {\n            var foundChoice = this._store.choices.find(function (choice) { return config.valueComparer(choice.value, value); });\n            if (foundChoice) {\n                if (this._isSelectElement) {\n                    // for exact matches, do not prompt to add it as a custom choice\n                    this._displayNotice('', NoticeTypes.addChoice);\n                    return false;\n                }\n                if (!config.duplicateItemsAllowed) {\n                    canAddItem = false;\n                    notice = resolveNoticeFunction(config.uniqueItemText, value, undefined);\n                }\n            }\n        }\n        if (canAddItem) {\n            notice = resolveNoticeFunction(config.addItemText, value, undefined);\n        }\n        if (notice) {\n            this._displayNotice(notice, NoticeTypes.addChoice);\n        }\n        return canAddItem;\n    };\n    Choices.prototype._searchChoices = function (value) {\n        var newValue = value.trim().replace(/\\s{2,}/, ' ');\n        // signal input didn't change search\n        if (!newValue.length || newValue === this._currentValue) {\n            return null;\n        }\n        var searcher = this._searcher;\n        if (searcher.isEmptyIndex()) {\n            searcher.index(this._store.searchableChoices);\n        }\n        // If new value matches the desired length and is not the same as the current value with a space\n        var results = searcher.search(newValue);\n        this._currentValue = newValue;\n        this._highlightPosition = 0;\n        this._isSearching = true;\n        var notice = this._notice;\n        var noticeType = notice && notice.type;\n        if (noticeType !== NoticeTypes.addChoice) {\n            if (!results.length) {\n                this._displayNotice(resolveStringFunction(this.config.noResultsText), NoticeTypes.noResults);\n            }\n            else {\n                this._clearNotice();\n            }\n        }\n        this._store.dispatch(filterChoices(results));\n        return results.length;\n    };\n    Choices.prototype._stopSearch = function () {\n        if (this._isSearching) {\n            this._currentValue = '';\n            this._isSearching = false;\n            this._clearNotice();\n            this._store.dispatch(activateChoices(true));\n            this.passedElement.triggerEvent(EventType.search, {\n                value: '',\n                resultCount: 0,\n            });\n        }\n    };\n    Choices.prototype._addEventListeners = function () {\n        var documentElement = this._docRoot;\n        var outerElement = this.containerOuter.element;\n        var inputElement = this.input.element;\n        var passedElement = this.passedElement.element;\n        // capture events - can cancel event processing or propagation\n        documentElement.addEventListener('touchend', this._onTouchEnd, true);\n        outerElement.addEventListener('keydown', this._onKeyDown, true);\n        outerElement.addEventListener('mousedown', this._onMouseDown, true);\n        // passive events - doesn't call `preventDefault` or `stopPropagation`\n        documentElement.addEventListener('click', this._onClick, { passive: true });\n        documentElement.addEventListener('touchmove', this._onTouchMove, {\n            passive: true,\n        });\n        this.dropdown.element.addEventListener('mouseover', this._onMouseOver, {\n            passive: true,\n        });\n        if (this._isSelectOneElement) {\n            outerElement.addEventListener('focus', this._onFocus, {\n                passive: true,\n            });\n            outerElement.addEventListener('blur', this._onBlur, {\n                passive: true,\n            });\n        }\n        inputElement.addEventListener('keyup', this._onKeyUp, {\n            passive: true,\n        });\n        inputElement.addEventListener('input', this._onInput, {\n            passive: true,\n        });\n        inputElement.addEventListener('focus', this._onFocus, {\n            passive: true,\n        });\n        inputElement.addEventListener('blur', this._onBlur, {\n            passive: true,\n        });\n        if (inputElement.form) {\n            inputElement.form.addEventListener('reset', this._onFormReset, {\n                passive: true,\n            });\n        }\n        if (passedElement.hasAttribute('required')) {\n            passedElement.addEventListener('change', this._onChange, {\n                passive: true,\n            });\n            passedElement.addEventListener('invalid', this._onInvalid, {\n                passive: true,\n            });\n        }\n        this.input.addEventListeners();\n    };\n    Choices.prototype._removeEventListeners = function () {\n        var documentElement = this._docRoot;\n        var outerElement = this.containerOuter.element;\n        var inputElement = this.input.element;\n        var passedElement = this.passedElement.element;\n        documentElement.removeEventListener('touchend', this._onTouchEnd, true);\n        outerElement.removeEventListener('keydown', this._onKeyDown, true);\n        outerElement.removeEventListener('mousedown', this._onMouseDown, true);\n        documentElement.removeEventListener('click', this._onClick);\n        documentElement.removeEventListener('touchmove', this._onTouchMove);\n        this.dropdown.element.removeEventListener('mouseover', this._onMouseOver);\n        if (this._isSelectOneElement) {\n            outerElement.removeEventListener('focus', this._onFocus);\n            outerElement.removeEventListener('blur', this._onBlur);\n        }\n        inputElement.removeEventListener('keyup', this._onKeyUp);\n        inputElement.removeEventListener('input', this._onInput);\n        inputElement.removeEventListener('focus', this._onFocus);\n        inputElement.removeEventListener('blur', this._onBlur);\n        if (inputElement.form) {\n            inputElement.form.removeEventListener('reset', this._onFormReset);\n        }\n        if (passedElement.hasAttribute('required')) {\n            passedElement.removeEventListener('change', this._onChange);\n            passedElement.removeEventListener('invalid', this._onInvalid);\n        }\n        this.input.removeEventListeners();\n    };\n    Choices.prototype._onKeyDown = function (event) {\n        var keyCode = event.keyCode;\n        var hasActiveDropdown = this.dropdown.isActive;\n        /*\n        See:\n        https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key\n        https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values\n        https://en.wikipedia.org/wiki/UTF-16#Code_points_from_U+010000_to_U+10FFFF - UTF-16 surrogate pairs\n        https://stackoverflow.com/a/70866532 - \"Unidentified\" for mobile\n        http://www.unicode.org/versions/Unicode5.2.0/ch16.pdf#G19635 - U+FFFF is reserved (Section 16.7)\n    \n        Logic: when a key event is sent, `event.key` represents its printable value _or_ one\n        of a large list of special values indicating meta keys/functionality. In addition,\n        key events for compose functionality contain a value of `Dead` when mid-composition.\n    \n        I can't quite verify it, but non-English IMEs may also be able to generate key codes\n        for code points in the surrogate-pair range, which could potentially be seen as having\n        key.length > 1. Since `Fn` is one of the special keys, we can't distinguish by that\n        alone.\n    \n        Here, key.length === 1 means we know for sure the input was printable and not a special\n        `key` value. When the length is greater than 1, it could be either a printable surrogate\n        pair or a special `key` value. We can tell the difference by checking if the _character\n        code_ value (not code point!) is in the \"surrogate pair\" range or not.\n    \n        We don't use .codePointAt because an invalid code point would return 65535, which wouldn't\n        pass the >= 0x10000 check we would otherwise use.\n    \n        > ...The Unicode Standard sets aside 66 noncharacter code points. The last two code points\n        > of each plane are noncharacters: U+FFFE and U+FFFF on the BMP...\n        */\n        var wasPrintableChar = event.key.length === 1 ||\n            (event.key.length === 2 && event.key.charCodeAt(0) >= 0xd800) ||\n            event.key === 'Unidentified';\n        /*\n          We do not show the dropdown if focusing out with esc or navigating through input fields.\n          An activated search can still be opened with any other key.\n         */\n        if (!this._isTextElement &&\n            !hasActiveDropdown &&\n            keyCode !== KeyCodeMap.ESC_KEY &&\n            keyCode !== KeyCodeMap.TAB_KEY &&\n            keyCode !== KeyCodeMap.SHIFT_KEY) {\n            this.showDropdown();\n            if (!this.input.isFocussed && wasPrintableChar) {\n                /*\n                  We update the input value with the pressed key as\n                  the input was not focussed at the time of key press\n                  therefore does not have the value of the key.\n                */\n                this.input.value += event.key;\n                // browsers interpret a space as pagedown\n                if (event.key === ' ') {\n                    event.preventDefault();\n                }\n            }\n        }\n        switch (keyCode) {\n            case KeyCodeMap.A_KEY:\n                return this._onSelectKey(event, this.itemList.element.hasChildNodes());\n            case KeyCodeMap.ENTER_KEY:\n                return this._onEnterKey(event, hasActiveDropdown);\n            case KeyCodeMap.ESC_KEY:\n                return this._onEscapeKey(event, hasActiveDropdown);\n            case KeyCodeMap.UP_KEY:\n            case KeyCodeMap.PAGE_UP_KEY:\n            case KeyCodeMap.DOWN_KEY:\n            case KeyCodeMap.PAGE_DOWN_KEY:\n                return this._onDirectionKey(event, hasActiveDropdown);\n            case KeyCodeMap.DELETE_KEY:\n            case KeyCodeMap.BACK_KEY:\n                return this._onDeleteKey(event, this._store.items, this.input.isFocussed);\n        }\n    };\n    Choices.prototype._onKeyUp = function ( /* event: KeyboardEvent */) {\n        this._canSearch = this.config.searchEnabled;\n    };\n    Choices.prototype._onInput = function ( /* event: InputEvent */) {\n        var value = this.input.value;\n        if (!value) {\n            if (this._isTextElement) {\n                this.hideDropdown(true);\n            }\n            else {\n                this._stopSearch();\n            }\n            return;\n        }\n        if (!this._canAddItems()) {\n            return;\n        }\n        if (this._canSearch) {\n            // do the search even if the entered text can not be added\n            this._handleSearch(value);\n        }\n        if (!this._canAddUserChoices) {\n            return;\n        }\n        // determine if a notice needs to be displayed for why a search result can't be added\n        this._canCreateItem(value);\n        if (this._isSelectElement) {\n            this._highlightPosition = 0; // reset to select the notice and/or exact match\n            this._highlightChoice();\n        }\n    };\n    Choices.prototype._onSelectKey = function (event, hasItems) {\n        // If CTRL + A or CMD + A have been pressed and there are items to select\n        if ((event.ctrlKey || event.metaKey) && hasItems) {\n            this._canSearch = false;\n            var shouldHightlightAll = this.config.removeItems && !this.input.value && this.input.element === document.activeElement;\n            if (shouldHightlightAll) {\n                this.highlightAll();\n            }\n        }\n    };\n    Choices.prototype._onEnterKey = function (event, hasActiveDropdown) {\n        var _this = this;\n        var value = this.input.value;\n        var target = event.target;\n        event.preventDefault();\n        if (target && target.hasAttribute('data-button')) {\n            this._handleButtonAction(target);\n            return;\n        }\n        if (!hasActiveDropdown) {\n            if (this._isSelectElement || this._notice) {\n                this.showDropdown();\n            }\n            return;\n        }\n        var highlightedChoice = this.dropdown.element.querySelector(getClassNamesSelector(this.config.classNames.highlightedState));\n        if (highlightedChoice && this._handleChoiceAction(highlightedChoice)) {\n            return;\n        }\n        if (!target || !value) {\n            this.hideDropdown(true);\n            return;\n        }\n        if (!this._canAddItems()) {\n            return;\n        }\n        var addedItem = false;\n        this._store.withTxn(function () {\n            addedItem = _this._findAndSelectChoiceByValue(value, true);\n            if (!addedItem) {\n                if (!_this._canAddUserChoices) {\n                    return;\n                }\n                if (!_this._canCreateItem(value)) {\n                    return;\n                }\n                _this._addChoice(mapInputToChoice(value, false, _this.config.allowHtmlUserInput), true, true);\n                addedItem = true;\n            }\n            _this.clearInput();\n            _this.unhighlightAll();\n        });\n        if (!addedItem) {\n            return;\n        }\n        this._triggerChange(value);\n        if (this.config.closeDropdownOnSelect) {\n            this.hideDropdown(true);\n        }\n    };\n    Choices.prototype._onEscapeKey = function (event, hasActiveDropdown) {\n        if (hasActiveDropdown) {\n            event.stopPropagation();\n            this.hideDropdown(true);\n            this._stopSearch();\n            this.containerOuter.element.focus();\n        }\n    };\n    Choices.prototype._onDirectionKey = function (event, hasActiveDropdown) {\n        var keyCode = event.keyCode;\n        // If up or down key is pressed, traverse through options\n        if (hasActiveDropdown || this._isSelectOneElement) {\n            this.showDropdown();\n            this._canSearch = false;\n            var directionInt = keyCode === KeyCodeMap.DOWN_KEY || keyCode === KeyCodeMap.PAGE_DOWN_KEY ? 1 : -1;\n            var skipKey = event.metaKey || keyCode === KeyCodeMap.PAGE_DOWN_KEY || keyCode === KeyCodeMap.PAGE_UP_KEY;\n            var nextEl = void 0;\n            if (skipKey) {\n                if (directionInt > 0) {\n                    nextEl = this.dropdown.element.querySelector(\"\".concat(selectableChoiceIdentifier, \":last-of-type\"));\n                }\n                else {\n                    nextEl = this.dropdown.element.querySelector(selectableChoiceIdentifier);\n                }\n            }\n            else {\n                var currentEl = this.dropdown.element.querySelector(getClassNamesSelector(this.config.classNames.highlightedState));\n                if (currentEl) {\n                    nextEl = getAdjacentEl(currentEl, selectableChoiceIdentifier, directionInt);\n                }\n                else {\n                    nextEl = this.dropdown.element.querySelector(selectableChoiceIdentifier);\n                }\n            }\n            if (nextEl) {\n                // We prevent default to stop the cursor moving\n                // when pressing the arrow\n                if (!isScrolledIntoView(nextEl, this.choiceList.element, directionInt)) {\n                    this.choiceList.scrollToChildElement(nextEl, directionInt);\n                }\n                this._highlightChoice(nextEl);\n            }\n            // Prevent default to maintain cursor position whilst\n            // traversing dropdown options\n            event.preventDefault();\n        }\n    };\n    Choices.prototype._onDeleteKey = function (event, items, hasFocusedInput) {\n        // If backspace or delete key is pressed and the input has no value\n        if (!this._isSelectOneElement && !event.target.value && hasFocusedInput) {\n            this._handleBackspace(items);\n            event.preventDefault();\n        }\n    };\n    Choices.prototype._onTouchMove = function () {\n        if (this._wasTap) {\n            this._wasTap = false;\n        }\n    };\n    Choices.prototype._onTouchEnd = function (event) {\n        var target = (event || event.touches[0]).target;\n        var touchWasWithinContainer = this._wasTap && this.containerOuter.element.contains(target);\n        if (touchWasWithinContainer) {\n            var containerWasExactTarget = target === this.containerOuter.element || target === this.containerInner.element;\n            if (containerWasExactTarget) {\n                if (this._isTextElement) {\n                    this.input.focus();\n                }\n                else if (this._isSelectMultipleElement) {\n                    this.showDropdown();\n                }\n            }\n            // Prevents focus event firing\n            event.stopPropagation();\n        }\n        this._wasTap = true;\n    };\n    /**\n     * Handles mousedown event in capture mode for containetOuter.element\n     */\n    Choices.prototype._onMouseDown = function (event) {\n        var target = event.target;\n        if (!(target instanceof Element)) {\n            return;\n        }\n        // If we have our mouse down on the scrollbar and are on IE11...\n        if (IS_IE11 && this.choiceList.element.contains(target)) {\n            // check if click was on a scrollbar area\n            var firstChoice = this.choiceList.element.firstElementChild;\n            this._isScrollingOnIe =\n                this._direction === 'ltr' ? event.offsetX >= firstChoice.offsetWidth : event.offsetX < firstChoice.offsetLeft;\n        }\n        if (target === this.input.element) {\n            return;\n        }\n        var item = target.closest('[data-button],[data-item],[data-choice]');\n        if (item instanceof HTMLElement) {\n            if ('button' in item.dataset) {\n                this._handleButtonAction(item);\n            }\n            else if ('item' in item.dataset) {\n                this._handleItemAction(item, event.shiftKey);\n            }\n            else if ('choice' in item.dataset) {\n                this._handleChoiceAction(item);\n            }\n        }\n        event.preventDefault();\n    };\n    /**\n     * Handles mouseover event over this.dropdown\n     * @param {MouseEvent} event\n     */\n    Choices.prototype._onMouseOver = function (_a) {\n        var target = _a.target;\n        if (target instanceof HTMLElement && 'choice' in target.dataset) {\n            this._highlightChoice(target);\n        }\n    };\n    Choices.prototype._onClick = function (_a) {\n        var target = _a.target;\n        var containerOuter = this.containerOuter;\n        var clickWasWithinContainer = containerOuter.element.contains(target);\n        if (clickWasWithinContainer) {\n            if (!this.dropdown.isActive && !containerOuter.isDisabled) {\n                if (this._isTextElement) {\n                    if (document.activeElement !== this.input.element) {\n                        this.input.focus();\n                    }\n                }\n                else {\n                    this.showDropdown();\n                    containerOuter.element.focus();\n                }\n            }\n            else if (this._isSelectOneElement &&\n                target !== this.input.element &&\n                !this.dropdown.element.contains(target)) {\n                this.hideDropdown();\n            }\n        }\n        else {\n            containerOuter.removeFocusState();\n            this.hideDropdown(true);\n            this.unhighlightAll();\n        }\n    };\n    Choices.prototype._onFocus = function (_a) {\n        var target = _a.target;\n        var containerOuter = this.containerOuter;\n        var focusWasWithinContainer = target && containerOuter.element.contains(target);\n        if (!focusWasWithinContainer) {\n            return;\n        }\n        var targetIsInput = target === this.input.element;\n        if (this._isTextElement) {\n            if (targetIsInput) {\n                containerOuter.addFocusState();\n            }\n        }\n        else if (this._isSelectMultipleElement) {\n            if (targetIsInput) {\n                this.showDropdown(true);\n                // If element is a select box, the focused element is the container and the dropdown\n                // isn't already open, focus and show dropdown\n                containerOuter.addFocusState();\n            }\n        }\n        else {\n            containerOuter.addFocusState();\n            if (targetIsInput) {\n                this.showDropdown(true);\n            }\n        }\n    };\n    Choices.prototype._onBlur = function (_a) {\n        var target = _a.target;\n        var containerOuter = this.containerOuter;\n        var blurWasWithinContainer = target && containerOuter.element.contains(target);\n        if (blurWasWithinContainer && !this._isScrollingOnIe) {\n            if (target === this.input.element) {\n                containerOuter.removeFocusState();\n                this.hideDropdown(true);\n                if (this._isTextElement || this._isSelectMultipleElement) {\n                    this.unhighlightAll();\n                }\n            }\n            else if (target === this.containerOuter.element) {\n                // Remove the focus state when the past outerContainer was the target\n                containerOuter.removeFocusState();\n                // Also close the dropdown if search is disabled\n                if (!this.config.searchEnabled) {\n                    this.hideDropdown(true);\n                }\n            }\n        }\n        else {\n            // On IE11, clicking the scollbar blurs our input and thus\n            // closes the dropdown. To stop this, we refocus our input\n            // if we know we are on IE *and* are scrolling.\n            this._isScrollingOnIe = false;\n            this.input.element.focus();\n        }\n    };\n    Choices.prototype._onFormReset = function () {\n        var _this = this;\n        this._store.withTxn(function () {\n            _this.clearInput();\n            _this.hideDropdown();\n            _this.refresh(false, false, true);\n            if (_this._initialItems.length) {\n                _this.setChoiceByValue(_this._initialItems);\n            }\n        });\n    };\n    Choices.prototype._onChange = function (event) {\n        if (!event.target.checkValidity()) {\n            return;\n        }\n        this.containerOuter.removeInvalidState();\n    };\n    Choices.prototype._onInvalid = function () {\n        this.containerOuter.addInvalidState();\n    };\n    /**\n     * Removes any highlighted choice options\n     */\n    Choices.prototype._removeHighlightedChoices = function () {\n        var highlightedState = this.config.classNames.highlightedState;\n        var highlightedChoices = Array.from(this.dropdown.element.querySelectorAll(getClassNamesSelector(highlightedState)));\n        // Remove any highlighted choices\n        highlightedChoices.forEach(function (choice) {\n            removeClassesFromElement(choice, highlightedState);\n            choice.setAttribute('aria-selected', 'false');\n        });\n    };\n    Choices.prototype._highlightChoice = function (el) {\n        if (el === void 0) { el = null; }\n        var choices = Array.from(this.dropdown.element.querySelectorAll(selectableChoiceIdentifier));\n        if (!choices.length) {\n            return;\n        }\n        var passedEl = el;\n        var highlightedState = this.config.classNames.highlightedState;\n        this._removeHighlightedChoices();\n        if (passedEl) {\n            this._highlightPosition = choices.indexOf(passedEl);\n        }\n        else {\n            // Highlight choice based on last known highlight location\n            if (choices.length > this._highlightPosition) {\n                // If we have an option to highlight\n                passedEl = choices[this._highlightPosition];\n            }\n            else {\n                // Otherwise highlight the option before\n                passedEl = choices[choices.length - 1];\n            }\n            if (!passedEl) {\n                passedEl = choices[0];\n            }\n        }\n        addClassesToElement(passedEl, highlightedState);\n        passedEl.setAttribute('aria-selected', 'true');\n        this.passedElement.triggerEvent(EventType.highlightChoice, {\n            el: passedEl,\n        });\n        if (this.dropdown.isActive) {\n            // IE11 ignores aria-label and blocks virtual keyboard\n            // if aria-activedescendant is set without a dropdown\n            this.input.setActiveDescendant(passedEl.id);\n            this.containerOuter.setActiveDescendant(passedEl.id);\n        }\n    };\n    Choices.prototype._addItem = function (item, withEvents, userTriggered) {\n        if (withEvents === void 0) { withEvents = true; }\n        if (userTriggered === void 0) { userTriggered = false; }\n        if (!item.id) {\n            throw new TypeError('item.id must be set before _addItem is called for a choice/item');\n        }\n        if (this.config.singleModeForMultiSelect || this._isSelectOneElement) {\n            this.removeActiveItems(item.id);\n        }\n        this._store.dispatch(addItem(item));\n        if (withEvents) {\n            var eventChoice = getChoiceForOutput(item);\n            this.passedElement.triggerEvent(EventType.addItem, eventChoice);\n            if (userTriggered) {\n                this.passedElement.triggerEvent(EventType.choice, eventChoice);\n            }\n        }\n    };\n    Choices.prototype._removeItem = function (item) {\n        if (!item.id) {\n            return;\n        }\n        this._store.dispatch(removeItem$1(item));\n        var notice = this._notice;\n        if (notice && notice.type === NoticeTypes.noChoices) {\n            this._clearNotice();\n        }\n        this.passedElement.triggerEvent(EventType.removeItem, getChoiceForOutput(item));\n    };\n    Choices.prototype._addChoice = function (choice, withEvents, userTriggered) {\n        if (withEvents === void 0) { withEvents = true; }\n        if (userTriggered === void 0) { userTriggered = false; }\n        if (choice.id) {\n            throw new TypeError('Can not re-add a choice which has already been added');\n        }\n        var config = this.config;\n        if (!config.duplicateItemsAllowed && this._store.choices.find(function (c) { return config.valueComparer(c.value, choice.value); })) {\n            return;\n        }\n        // Generate unique id, in-place update is required so chaining _addItem works as expected\n        this._lastAddedChoiceId++;\n        choice.id = this._lastAddedChoiceId;\n        choice.elementId = \"\".concat(this._baseId, \"-\").concat(this._idNames.itemChoice, \"-\").concat(choice.id);\n        var prependValue = config.prependValue, appendValue = config.appendValue;\n        if (prependValue) {\n            choice.value = prependValue + choice.value;\n        }\n        if (appendValue) {\n            choice.value += appendValue.toString();\n        }\n        if ((prependValue || appendValue) && choice.element) {\n            choice.element.value = choice.value;\n        }\n        this._clearNotice();\n        this._store.dispatch(addChoice(choice));\n        if (choice.selected) {\n            this._addItem(choice, withEvents, userTriggered);\n        }\n    };\n    Choices.prototype._addGroup = function (group, withEvents) {\n        var _this = this;\n        if (withEvents === void 0) { withEvents = true; }\n        if (group.id) {\n            throw new TypeError('Can not re-add a group which has already been added');\n        }\n        this._store.dispatch(addGroup(group));\n        if (!group.choices) {\n            return;\n        }\n        // add unique id for the group(s), and do not store the full list of choices in this group\n        this._lastAddedGroupId++;\n        group.id = this._lastAddedGroupId;\n        group.choices.forEach(function (item) {\n            item.group = group;\n            if (group.disabled) {\n                item.disabled = true;\n            }\n            _this._addChoice(item, withEvents);\n        });\n    };\n    Choices.prototype._createTemplates = function () {\n        var _this = this;\n        var callbackOnCreateTemplates = this.config.callbackOnCreateTemplates;\n        var userTemplates = {};\n        if (typeof callbackOnCreateTemplates === 'function') {\n            userTemplates = callbackOnCreateTemplates.call(this, strToEl, escapeForTemplate, getClassNames);\n        }\n        var templating = {};\n        Object.keys(this._templates).forEach(function (name) {\n            if (name in userTemplates) {\n                templating[name] = userTemplates[name].bind(_this);\n            }\n            else {\n                templating[name] = _this._templates[name].bind(_this);\n            }\n        });\n        this._templates = templating;\n    };\n    Choices.prototype._createElements = function () {\n        var templating = this._templates;\n        var _a = this, config = _a.config, isSelectOneElement = _a._isSelectOneElement;\n        var position = config.position, classNames = config.classNames;\n        var elementType = this._elementType;\n        this.containerOuter = new Container({\n            element: templating.containerOuter(config, this._direction, this._isSelectElement, isSelectOneElement, config.searchEnabled, elementType, config.labelId),\n            classNames: classNames,\n            type: elementType,\n            position: position,\n        });\n        this.containerInner = new Container({\n            element: templating.containerInner(config),\n            classNames: classNames,\n            type: elementType,\n            position: position,\n        });\n        this.input = new Input({\n            element: templating.input(config, this._placeholderValue),\n            classNames: classNames,\n            type: elementType,\n            preventPaste: !config.paste,\n        });\n        this.choiceList = new List({\n            element: templating.choiceList(config, isSelectOneElement),\n        });\n        this.itemList = new List({\n            element: templating.itemList(config, isSelectOneElement),\n        });\n        this.dropdown = new Dropdown({\n            element: templating.dropdown(config),\n            classNames: classNames,\n            type: elementType,\n        });\n    };\n    Choices.prototype._createStructure = function () {\n        var _a = this, containerInner = _a.containerInner, containerOuter = _a.containerOuter, passedElement = _a.passedElement;\n        var dropdownElement = this.dropdown.element;\n        // Hide original element\n        passedElement.conceal();\n        // Wrap input in container preserving DOM ordering\n        containerInner.wrap(passedElement.element);\n        // Wrapper inner container with outer container\n        containerOuter.wrap(containerInner.element);\n        containerOuter.element.appendChild(containerInner.element);\n        containerOuter.element.appendChild(dropdownElement);\n        containerInner.element.appendChild(this.itemList.element);\n        dropdownElement.appendChild(this.choiceList.element);\n        if (this._isSelectOneElement) {\n            this.input.placeholder = this.config.searchPlaceholderValue || '';\n            if (this.config.searchEnabled) {\n                dropdownElement.insertBefore(this.input.element, dropdownElement.firstChild);\n            }\n        }\n        else {\n            if (!this._isSelectMultipleElement || this.config.searchEnabled) {\n                containerInner.element.appendChild(this.input.element);\n            }\n            if (this._placeholderValue) {\n                this.input.placeholder = this._placeholderValue;\n            }\n            this.input.setWidth();\n        }\n        this._highlightPosition = 0;\n        this._isSearching = false;\n    };\n    Choices.prototype._initStore = function () {\n        var _this = this;\n        this._store.subscribe(this._render).withTxn(function () {\n            _this._addPredefinedChoices(_this._presetChoices, _this._isSelectOneElement && !_this._hasNonChoicePlaceholder, false);\n        });\n        if (!this._store.choices.length || (this._isSelectOneElement && this._hasNonChoicePlaceholder)) {\n            this._render();\n        }\n    };\n    Choices.prototype._addPredefinedChoices = function (choices, selectFirstOption, withEvents) {\n        var _this = this;\n        if (selectFirstOption === void 0) { selectFirstOption = false; }\n        if (withEvents === void 0) { withEvents = true; }\n        if (selectFirstOption) {\n            /**\n             * If there is a selected choice already or the choice is not the first in\n             * the array, add each choice normally.\n             *\n             * Otherwise we pre-select the first enabled choice in the array (\"select-one\" only)\n             */\n            var noSelectedChoices = choices.findIndex(function (choice) { return choice.selected; }) === -1;\n            if (noSelectedChoices) {\n                choices.some(function (choice) {\n                    if (choice.disabled || 'choices' in choice) {\n                        return false;\n                    }\n                    choice.selected = true;\n                    return true;\n                });\n            }\n        }\n        choices.forEach(function (item) {\n            if ('choices' in item) {\n                if (_this._isSelectElement) {\n                    _this._addGroup(item, withEvents);\n                }\n            }\n            else {\n                _this._addChoice(item, withEvents);\n            }\n        });\n    };\n    Choices.prototype._findAndSelectChoiceByValue = function (value, userTriggered) {\n        var _this = this;\n        if (userTriggered === void 0) { userTriggered = false; }\n        // Check 'value' property exists and the choice isn't already selected\n        var foundChoice = this._store.choices.find(function (choice) { return _this.config.valueComparer(choice.value, value); });\n        if (foundChoice && !foundChoice.disabled && !foundChoice.selected) {\n            this._addItem(foundChoice, true, userTriggered);\n            return true;\n        }\n        return false;\n    };\n    Choices.prototype._generatePlaceholderValue = function () {\n        var config = this.config;\n        if (!config.placeholder) {\n            return null;\n        }\n        if (this._hasNonChoicePlaceholder) {\n            return config.placeholderValue;\n        }\n        if (this._isSelectElement) {\n            var placeholderOption = this.passedElement.placeholderOption;\n            return placeholderOption ? placeholderOption.text : null;\n        }\n        return null;\n    };\n    Choices.prototype._warnChoicesInitFailed = function (caller) {\n        if (this.config.silent) {\n            return;\n        }\n        if (!this.initialised) {\n            throw new TypeError(\"\".concat(caller, \" called on a non-initialised instance of Choices\"));\n        }\n        else if (!this.initialisedOK) {\n            throw new TypeError(\"\".concat(caller, \" called for an element which has multiple instances of Choices initialised on it\"));\n        }\n    };\n    Choices.version = '11.2.1';\n    return Choices;\n}());\n\nexport { Choices as default };\n"
  },
  {
    "path": "public/assets/styles/base.css",
    "content": "/* =============================================\n=            Generic styling                  =\n============================================= */\n:root {\n  --color-primary: #005F75;\n}\n\n@media (prefers-color-scheme: dark) {\n  :root {\n    /* Demo defaults */\n    --body-bg: #272a2b;\n    --text-color: #cacaca;\n    --color-primary: #38daff;\n    --section-bg: #181a1b;\n    --section-color: #cacaca;\n    --hr-border: #373a3d;\n    --choices-primary-color: #38daff;\n    --choices-item-color: black;\n    --choices-bg-color: #101010;\n    --choices-bg-color-dropdown: #101010;\n    --choices-keyline-color: #3b3e40;\n    --choices-bg-color-disabled: #181a1b;\n    --choices-item-disabled-color: #eee;\n    --choices-disabled-color: #2d2d2d;\n    --choices-highlighted-color: #16292d;\n    --choices-icon-cross: url(\"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjEiIHZpZXdCb3g9IjAgMCAyMSAyMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSIjMDAwIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0yLjU5Mi4wNDRsMTguMzY0IDE4LjM2NC0yLjU0OCAyLjU0OEwuMDQ0IDIuNTkyeiIvPjxwYXRoIGQ9Ik0wIDE4LjM2NEwxOC4zNjQgMGwyLjU0OCAyLjU0OEwyLjU0OCAyMC45MTJ6Ii8+PC9nPjwvc3ZnPg==\");\n    --choices-icon-cross-inverse: url(\"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjEiIHZpZXdCb3g9IjAgMCAyMSAyMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSIjRkZGIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0yLjU5Mi4wNDRsMTguMzY0IDE4LjM2NC0yLjU0OCAyLjU0OEwuMDQ0IDIuNTkyeiIvPjxwYXRoIGQ9Ik0wIDE4LjM2NEwxOC4zNjQgMGwyLjU0OCAyLjU0OEwyLjU0OCAyMC45MTJ6Ii8+PC9nPjwvc3ZnPg==\");\n    color-scheme: dark;\n  }\n  input, select {\n    color: #fff;\n  }\n}\n* {\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n\n*,\n*::before,\n*::after {\n  box-sizing: border-box;\n}\n\nhtml,\nbody {\n  position: relative;\n  margin: 0;\n  width: 100%;\n  height: 100%;\n}\n\nbody {\n  font-family: \"Helvetica Neue\", Helvetica, Arial, \"Lucida Grande\", sans-serif;\n  font-size: 16px;\n  line-height: 1.4;\n  color: var(--text-color, #fff);\n  background-color: var(--body-bg, #333);\n  overflow-x: hidden;\n}\n\nlabel {\n  display: block;\n  margin-bottom: 8px;\n  font-size: 14px;\n  font-weight: 500;\n  cursor: pointer;\n}\n\np {\n  margin-top: 0;\n  margin-bottom: 8px;\n}\n\nhr {\n  display: block;\n  margin: 30px 0;\n  border: 0;\n  border-bottom: 1px solid var(--hr-border, #eaeaea);\n  height: 1px;\n}\n\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n  margin-top: 0;\n  margin-bottom: 12px;\n  font-weight: 400;\n  line-height: 1.2;\n}\n\na,\na:visited,\na:focus {\n  color: var(--link-color, #fff);\n  text-decoration: none;\n  font-weight: 600;\n}\n\n.form-control {\n  display: block;\n  width: 100%;\n  background-color: var(--form-bg, #f9f9f9);\n  padding: 12px;\n  border: 1px solid var(--form-boder, #ddd);\n  border-radius: 2.5px;\n  font-size: 14px;\n  appearance: none;\n  margin-bottom: 24px;\n}\n\nh1,\n.h1 {\n  font-size: 32px;\n}\n\nh2,\n.h2 {\n  font-size: 24px;\n}\n\nh3,\n.h3 {\n  font-size: 20px;\n}\n\nh4,\n.h4 {\n  font-size: 18px;\n}\n\nh5,\n.h5 {\n  font-size: 16px;\n}\n\nh6,\n.h6 {\n  font-size: 14px;\n}\n\nlabel + p {\n  margin-top: -4px;\n}\n\n.container {\n  display: block;\n  margin: auto;\n  max-width: 40em;\n  padding: 48px;\n}\n@media (max-width: 620px) {\n  .container {\n    padding: 0;\n  }\n}\n\n.section {\n  background-color: var(--section-bg, #fff);\n  padding: 24px;\n  color: var(--section-color, #333);\n}\n.section a,\n.section a:visited,\n.section a:focus {\n  color: var(--link-color-section, var(--color-primary));\n}\n\n.logo {\n  display: block;\n  margin-bottom: 12px;\n}\n\n.logo-img {\n  width: 100%;\n  height: auto;\n  display: inline-block;\n  max-width: 100%;\n  vertical-align: top;\n  padding: 6px 0;\n}\n\n.visible-ie {\n  display: none;\n}\n\n.push-bottom {\n  margin-bottom: 24px;\n}\n\n.zero-bottom {\n  margin-bottom: 0;\n}\n\n.zero-top {\n  margin-top: 0;\n}\n\n.text-center {\n  text-align: center;\n}\n\n[data-test-hook] {\n  margin-bottom: 24px;\n}\n\n/* =====  End of Section comment block  ====== */\n"
  },
  {
    "path": "public/assets/styles/choices.css",
    "content": "/* ===============================\n=            Choices            =\n=============================== */\n.choices {\n  position: relative;\n  overflow: hidden;\n  margin-bottom: var(--choices-guttering, 24px);\n  font-size: var(--choices-font-size-lg, 16px);\n}\n.choices:focus {\n  outline: none;\n}\n.choices:last-child {\n  margin-bottom: 0;\n}\n.choices.is-open {\n  overflow: visible;\n}\n.choices.is-disabled :is(.choices__inner, .choices__input) {\n  background-color: var(--choices-bg-color-disabled, #eaeaea);\n  cursor: not-allowed !important;\n  -webkit-user-select: none;\n          user-select: none;\n}\n.choices.is-disabled .choices__item {\n  cursor: not-allowed;\n  color: var(--choices-item-disabled-color, #fff);\n}\n.choices [hidden] {\n  position: absolute;\n  inset: 0;\n  pointer-events: none;\n  opacity: 0;\n}\n\n.choices[data-type*=select-one] {\n  cursor: pointer;\n}\n.choices[data-type*=select-one] .choices__inner {\n  padding-bottom: var(--choices-inner-one-padding, 7.5px);\n}\n.choices[data-type*=select-one] .choices__input {\n  display: block;\n  width: var(--choices-width, 100%);\n  padding: var(--choices-dropdown-item-padding, 10px);\n  border-bottom: var(--choices-base-border, 1px solid) var(--choices-keyline-color, #ddd);\n  background-color: var(--choices-bg-color-dropdown, #fff);\n  margin: 0;\n}\n.choices[data-type*=select-one] .choices__button {\n  background-image: var(--choices-icon-cross-inverse, url(\"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjEiIHZpZXdCb3g9IjAgMCAyMSAyMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSIjMDAwIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0yLjU5Mi4wNDRsMTguMzY0IDE4LjM2NC0yLjU0OCAyLjU0OEwuMDQ0IDIuNTkyeiIvPjxwYXRoIGQ9Ik0wIDE4LjM2NEwxOC4zNjQgMGwyLjU0OCAyLjU0OEwyLjU0OCAyMC45MTJ6Ii8+PC9nPjwvc3ZnPg==\"));\n  padding: 0;\n  background-size: 8px;\n  position: absolute;\n  top: 50%;\n  right: 0;\n  margin-top: -10px;\n  margin-right: 25px;\n  height: 20px;\n  width: 20px;\n  border-radius: 10em;\n  opacity: 0.25;\n}\n.choices[data-type*=select-one] .choices__button:is(:hover, :focus) {\n  opacity: var(--choices-button-opacity-hover, 1);\n}\n.choices[data-type*=select-one] .choices__button:focus {\n  box-shadow: 0 0 0 2px var(--choices-highlight-color, #005F75);\n}\n.choices[data-type*=select-one] .choices__item[data-placeholder] .choices__button {\n  display: none;\n}\n.choices[data-type*=select-one]::after {\n  content: \"\";\n  height: 0;\n  width: 0;\n  border-style: solid;\n  border-color: var(--choices-text-color, #333) transparent transparent transparent;\n  border-width: var(--choices-arrow-size, 5px);\n  position: absolute;\n  right: var(--choices-arrow-right, 11.5px);\n  top: 50%;\n  margin-top: var(--choices-arrow-margin-top, -2.5px);\n  pointer-events: none;\n}\n.choices[data-type*=select-one].is-open::after {\n  border-color: transparent transparent var(--choices-text-color, #333);\n  margin-top: var(--choices-arrow-margin-top-open, -7.5px);\n}\n.choices[data-type*=select-one][dir=rtl]::after {\n  left: 11.5px;\n  right: auto;\n}\n.choices[data-type*=select-one][dir=rtl] .choices__button {\n  right: auto;\n  left: 0;\n  margin-left: 25px;\n  margin-right: 0;\n}\n\n.choices:is([data-type*=select-multiple], [data-type*=text]) .choices__inner {\n  cursor: text;\n}\n.choices:is([data-type*=select-multiple], [data-type*=text]) .choices__button {\n  position: relative;\n  display: inline-block;\n  margin: 0 calc(var(--choices-button-offset, 8px) * -0.5) 0 var(--choices-button-offset, 8px);\n  padding-left: calc(var(--choices-button-offset, 8px) * 2);\n  border-left: 1px solid color-mix(in srgb, var(--choices-primary-color, #005F75) 90%, var(--choices-darken, black));\n  background-image: var(--choices-icon-cross, url(\"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjEiIHZpZXdCb3g9IjAgMCAyMSAyMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSIjRkZGIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0yLjU5Mi4wNDRsMTguMzY0IDE4LjM2NC0yLjU0OCAyLjU0OEwuMDQ0IDIuNTkyeiIvPjxwYXRoIGQ9Ik0wIDE4LjM2NEwxOC4zNjQgMGwyLjU0OCAyLjU0OEwyLjU0OCAyMC45MTJ6Ii8+PC9nPjwvc3ZnPg==\"));\n  background-size: var(--choices-button-dimension, 8px);\n  width: var(--choices-button-dimension, 8px);\n  line-height: var(--choices-button-line-height, 1);\n  border-radius: var(--choices-button-border-radius, 0);\n  opacity: var(--choices-button-opacity, 0.75);\n}\n.choices:is([data-type*=select-multiple], [data-type*=text]) .choices__button:is(:hover, :focus) {\n  --choices-button-opacity: var(--choices-button-opacity-hover, 1);\n}\n\n.choices__inner {\n  display: inline-block;\n  vertical-align: top;\n  width: var(--choices-width, 100%);\n  background-color: var(--choices-bg-color, #f9f9f9);\n  padding: var(--choices-inner-padding, 7.5px 7.5px 3.75px);\n  border: var(--choices-base-border, 1px solid) var(--choices-keyline-color, #ddd);\n  border-radius: var(--choices-border-radius, 2.5px);\n  font-size: var(--choices-font-size-md, 14px);\n  min-height: var(--choices-input-height, 44px);\n  overflow: hidden;\n}\n.is-focused .choices__inner, .is-open .choices__inner {\n  border-color: color-mix(in srgb, var(--choices-keyline-color, #ddd) 85%, var(--choices-darken, black));\n}\n.is-open .choices__inner {\n  border-radius: var(--choices-border-radius, 2.5px) var(--choices-border-radius, 2.5px) 0 0;\n}\n.is-invalid .choices__inner {\n  border-color: var(--choices-invalid-color, #d33141);\n}\n.is-flipped.is-open .choices__inner {\n  border-radius: 0 0 var(--choices-border-radius, 2.5px) var(--choices-border-radius, 2.5px);\n}\n\n.choices__list {\n  margin: 0;\n  padding-left: 0;\n  list-style: none;\n}\n.choices__list--single {\n  display: inline-block;\n  padding: var(--choices-list-single-padding, 4px 16px 4px 4px);\n  width: var(--choices-width, 100%);\n}\n[dir=rtl] .choices__list--single {\n  padding-right: 4px;\n  padding-left: 16px;\n}\n.choices__list--single .choices__item {\n  width: var(--choices-width, 100%);\n}\n\n.choices__list--multiple {\n  display: inline;\n}\n.choices__list--multiple .choices__item {\n  display: inline-block;\n  vertical-align: middle;\n  border-radius: var(--choices-border-radius-item, 20px);\n  padding: var(--choices-multiple-item-padding, 4px 10px);\n  font-size: var(--choices-font-size-sm, 12px);\n  font-weight: 500;\n  margin-right: var(--choices-multiple-item-margin, 3.75px);\n  margin-bottom: var(--choices-multiple-item-margin, 3.75px);\n  background-color: var(--choices-primary-color, #005F75);\n  border: 1px solid color-mix(in srgb, var(--choices-primary-color, #005F75) 95%, var(--choices-darken, black));\n  color: var(--choices-item-color, #fff);\n  word-break: break-all;\n  box-sizing: border-box;\n}\n.choices__list--multiple .choices__item[data-deletable] {\n  padding-right: 5px;\n}\n[dir=rtl] .choices__list--multiple .choices__item {\n  margin-right: 0;\n  margin-left: var(--choices-multiple-item-margin, 3.75px);\n}\n.choices__list--multiple .choices__item.is-highlighted {\n  background-color: color-mix(in srgb, var(--choices-primary-color, #005F75) 95%, var(--choices-darken, black));\n  border: 1px solid color-mix(in srgb, var(--choices-primary-color, #005F75) 90%, var(--choices-darken, black));\n}\n.is-disabled .choices__list--multiple .choices__item {\n  background-color: color-mix(in srgb, var(--choices-disabled-color, #eaeaea) 75%, var(--choices-darken, black));\n  border: 1px solid color-mix(in srgb, var(--choices-disabled-color, #eaeaea) 65%, var(--choices-darken, black));\n}\n\n.choices__list--dropdown, .choices__list[aria-expanded] {\n  display: none;\n  z-index: var(--choices-z-index, 1);\n  position: absolute;\n  width: var(--choices-width, 100%);\n  background-color: var(--choices-bg-color-dropdown, #fff);\n  border: var(--choices-base-border, 1px solid) var(--choices-keyline-color, #ddd);\n  top: 100%;\n  margin-top: -1px;\n  border-bottom-left-radius: var(--choices-border-radius, 2.5px);\n  border-bottom-right-radius: var(--choices-border-radius, 2.5px);\n  overflow: hidden;\n  word-break: break-all;\n}\n.is-active.choices__list--dropdown, .is-active.choices__list[aria-expanded] {\n  display: block;\n}\n.is-open .choices__list--dropdown, .is-open .choices__list[aria-expanded] {\n  border-color: color-mix(in srgb, var(--choices-keyline-color, #ddd) 85%, var(--choices-darken, black));\n}\n.is-flipped .choices__list--dropdown, .is-flipped .choices__list[aria-expanded] {\n  top: auto;\n  bottom: 100%;\n  margin-top: 0;\n  margin-bottom: -1px;\n  border-radius: 0.25rem 0.25rem 0 0;\n}\n.choices__list--dropdown .choices__list, .choices__list[aria-expanded] .choices__list {\n  position: relative;\n  max-height: 300px;\n  overflow: auto;\n  -webkit-overflow-scrolling: touch;\n  will-change: scroll-position;\n}\n.choices__list--dropdown .choices__item, .choices__list[aria-expanded] .choices__item {\n  position: relative;\n  padding: var(--choices-dropdown-item-padding, 10px);\n  font-size: var(--choices-font-size-md, 14px);\n}\n[dir=rtl] .choices__list--dropdown .choices__item, [dir=rtl] .choices__list[aria-expanded] .choices__item {\n  text-align: right;\n}\n@media (min-width: 640px) {\n  .choices__list--dropdown .choices__item--selectable.is-highlighted[data-select-text], .choices__list[aria-expanded] .choices__item--selectable.is-highlighted[data-select-text] {\n    padding-right: 100px;\n  }\n  .choices__list--dropdown .choices__item--selectable.is-highlighted[data-select-text]::after, .choices__list[aria-expanded] .choices__item--selectable.is-highlighted[data-select-text]::after {\n    content: attr(data-select-text);\n    font-size: var(--choices-font-size-sm, 12px);\n    position: absolute;\n    right: 10px;\n    top: 50%;\n    transform: translateY(-50%);\n  }\n  [dir=rtl] .choices__list--dropdown .choices__item--selectable.is-highlighted[data-select-text], [dir=rtl] .choices__list[aria-expanded] .choices__item--selectable.is-highlighted[data-select-text] {\n    text-align: right;\n    padding-left: 100px;\n    padding-right: 10px;\n  }\n  [dir=rtl] .choices__list--dropdown .choices__item--selectable.is-highlighted[data-select-text]::after, [dir=rtl] .choices__list[aria-expanded] .choices__item--selectable.is-highlighted[data-select-text]::after {\n    right: auto;\n    left: 10px;\n  }\n}\n.choices__list--dropdown .choices__item--selectable.is-selected::after, .choices__list[aria-expanded] .choices__item--selectable.is-selected::after {\n  content: none !important;\n}\n.choices__list--dropdown .choices__item--selectable.is-selected, .choices__list[aria-expanded] .choices__item--selectable.is-selected, .choices__list--dropdown .choices__item--selectable.is-highlighted, .choices__list[aria-expanded] .choices__item--selectable.is-highlighted {\n  background-color: var(--choices-highlighted-color, #f2f2f2);\n}\n\n.choices__item {\n  cursor: default;\n}\n\n.choices__item--selectable {\n  cursor: pointer;\n}\n\n.choices__item--disabled {\n  cursor: not-allowed;\n  -webkit-user-select: none;\n          user-select: none;\n  opacity: 0.5;\n}\n\n.choices__heading {\n  font-weight: 600;\n  font-size: 12px;\n  padding: 10px;\n  border-bottom: 1px solid color-mix(in srgb, var(--choices-keyline-color, #ddd) 90%, var(--choices-lighten, white));\n  color: gray;\n}\n\n.choices__button {\n  text-indent: -9999px;\n  appearance: none;\n  border: 0;\n  background-color: transparent;\n  background-repeat: no-repeat;\n  background-position: center;\n  cursor: pointer;\n}\n.choices__button:focus {\n  outline: none;\n}\n\n.choices__input {\n  display: inline-block;\n  vertical-align: baseline;\n  background-color: var(--choices-bg-color, #f9f9f9);\n  font-size: var(--choices-font-size-md, 14px);\n  margin-bottom: var(--choices-input-margin-bottom, 5px);\n  border: 0;\n  border-radius: 0;\n  max-width: var(--choices-width, 100%);\n  padding: var(--choices-input-padding, 4px 0 4px 2px);\n}\n.choices__input:focus {\n  outline: 0;\n}\n.choices__input::-webkit-search-decoration, .choices__input::-webkit-search-cancel-button, .choices__input::-webkit-search-results-button, .choices__input::-webkit-search-results-decoration {\n  display: none;\n}\n.choices__input::-ms-clear, .choices__input::-ms-reveal {\n  display: none;\n  width: 0;\n  height: 0;\n}\n[dir=rtl] .choices__input {\n  padding-right: 2px;\n  padding-left: 0;\n}\n\n.choices__placeholder {\n  opacity: var(--choices-placeholder-opacity, 0.5);\n}\n\n/* =====  End of Choices  ====== */\n"
  },
  {
    "path": "public/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta\n      name=\"viewport\"\n      content=\"width=device-width,initial-scale=1,viewport-fit=cover\"\n    />\n    <title>Choices</title>\n    <meta\n      name=\"description\"\n      itemprop=\"description\"\n      content=\"A lightweight, configurable select box/text input plugin. Similar to Select2 and Selectize but without the jQuery dependency.\"\n    />\n    <link\n      rel=\"apple-touch-icon\"\n      sizes=\"180x180\"\n      href=\"assets/images/apple-touch-icon.png\"\n    />\n    <link\n      rel=\"icon\"\n      type=\"image/png\"\n      href=\"assets/images/favicon-32x32.png\"\n      sizes=\"32x32\"\n    />\n    <link\n      rel=\"icon\"\n      type=\"image/png\"\n      href=\"assets/images/favicon-16x16.png\"\n      sizes=\"16x16\"\n    />\n    <link rel=\"manifest\" href=\"assets/images/manifest.json\" />\n    <link\n      rel=\"mask-icon\"\n      href=\"assets/images/safari-pinned-tab.svg\"\n      color=\"#005F75\"\n    />\n    <link rel=\"shortcut icon\" href=\"assets/images/favicon.ico\" />\n    <meta\n      name=\"msapplication-config\"\n      content=\"/assets/images/browserconfig.xml\"\n    />\n    <meta name=\"theme-color\" content=\"#ffffff\" />\n\n    <!-- Ignore these -->\n    <link rel=\"stylesheet\" href=\"assets/styles/base.min.css\" />\n    <!-- End ignore these -->\n\n    <!-- Optional includes -->\n    <script src=\"https://cdnjs.cloudflare.com/polyfill/v3/polyfill.min.js?version=4.8.0&features=Array.from%2CArray.prototype.find%2CArray.prototype.includes%2CSymbol%2CSymbol.iterator%2CDOMTokenList%2CObject.assign%2CCustomEvent%2CElement.prototype.classList%2CElement.prototype.closest%2CElement.prototype.dataset%2CElement.prototype.replaceChildren%2Cfetch\"></script>\n    <!-- End optional includes -->\n\n    <!-- Choices includes -->\n    <link rel=\"stylesheet\" href=\"assets/styles/choices.min.css\" />\n    <script src=\"assets/scripts/choices.js\"></script>\n    <!-- End Choices includes -->\n  </head>\n\n  <body>\n    <div class=\"container\">\n      <div class=\"section\">\n        <a href=\"https://github.com/Choices-js/Choices\" class=\"logo\">\n          <picture style=\"display: flex\">\n            <source media=\"(prefers-color-scheme: dark)\" srcset=\"assets/images/logo--dark.svg\" class=\"logo-img source-dark\">\n            <source media=\"(prefers-color-scheme: light)\" srcset=\"assets/images/logo.svg\" class=\"logo-img source-light\">\n            <img src=\"assets/images/logo.svg\" alt=\"Choices.js logo\" class=\"logo-img\">\n          </picture>\n          <h1 class=\"visible-ie\">Choices.js</h1>\n        </a>\n        <p>\n          Choices.js is a lightweight, configurable select box/text input\n          plugin. Similar to Select2 and Selectize but without the jQuery\n          dependency.\n        </p>\n        <p>\n          For all config options, visit the\n          <a href=\"https://github.com/Choices-js/Choices\">GitHub repo</a>.\n        </p>\n\n        <hr />\n        <p class=\"h4 text-center\">\n          <strong\n            >Interested in writing your own ES6 JavaScript plugins? Check out\n            <a href=\"https://ES6.io/friend/JOHNSON\">ES6.io</a> for great\n            tutorials! 💪🏼</strong\n          >\n        </p>\n        <p class=\"h4 text-center\">\n          <strong>Sponsored by:</strong>\n          <br />\n          <a href=\"https://wanderermaps.com/\" target=\"_blank\" rel=\"noopener noreferrer\">\n            <img src=\"https://cdn.shopify.com/s/files/1/0614/3357/7715/files/Logo_BlackWithBackground_150x.png?v=1644802773\" alt=\"Wanderer Maps logo\">\n          </a>\n        </p>\n        <hr />\n\n        <h2>Text inputs</h2>\n        <label for=\"choices-text-remove-button\"\n          >Limited to 5 values with remove button</label\n        >\n        <input\n          class=\"form-control\"\n          id=\"choices-text-remove-button\"\n          type=\"text\"\n          value=\"preset-1,preset-2\"\n          placeholder=\"Enter something\"\n        />\n\n        <label for=\"choices-text-unique-values\"\n          >Unique values only, no pasting</label\n        >\n        <input\n          class=\"form-control\"\n          id=\"choices-text-unique-values\"\n          type=\"text\"\n          value=\"preset-1, preset-2\"\n          placeholder=\"This is a placeholder\"\n          class=\"custom class\"\n        />\n\n        <label for=\"choices-text-email-filter\">Email addresses only</label>\n        <input\n          class=\"form-control\"\n          id=\"choices-text-email-filter\"\n          type=\"text\"\n          placeholder=\"This is a placeholder\"\n        />\n\n        <label for=\"choices-text-disabled\">Disabled</label>\n        <input\n          class=\"form-control\"\n          id=\"choices-text-disabled\"\n          type=\"text\"\n          value=\"josh@joshuajohnson.co.uk, joe@bloggs.co.uk\"\n          placeholder=\"This is a placeholder\"\n        />\n\n        <label for=\"choices-text-prepend-append-value\"\n          >Prepends and appends a value to each items return value</label\n        >\n        <input\n          class=\"form-control\"\n          id=\"choices-text-prepend-append-value\"\n          type=\"text\"\n          value=\"preset-1, preset-2\"\n          placeholder=\"This is a placeholder\"\n        />\n\n        <label for=\"choices-text-preset-values\"\n          >Preset values passed through options</label\n        >\n        <input\n          class=\"form-control\"\n          id=\"choices-text-preset-values\"\n          type=\"text\"\n          value=\"Michael Smith\"\n          placeholder=\"This is a placeholder\"\n        />\n\n        <label for=\"choices-text-i18n\">I18N labels</label>\n        <input class=\"form-control\" id=\"choices-text-i18n\" type=\"text\" />\n\n        <label for=\"choices-text-rtl\">Right-to-left</label>\n        <input\n          data-trigger\n          class=\"form-control\"\n          id=\"choices-text-rtl\"\n          type=\"text\"\n          value=\"Value 1, Value 2\"\n          dir=\"rtl\"\n        />\n\n        <hr />\n\n        <h2>Multiple select input</h2>\n        <label for=\"choices-multiple-default\">Default</label>\n        <select\n          class=\"form-control\"\n          data-trigger\n          name=\"choices-multiple-default\"\n          id=\"choices-multiple-default\"\n          placeholder=\"This is a placeholder\"\n          multiple\n        >\n          <option value=\"Choice 1\" selected>Choice 1</option>\n          <option value=\"Choice 2\">Choice 2</option>\n          <option value=\"Choice 3\">Choice 3</option>\n          <option value=\"Choice 4\" disabled>Choice 4</option>\n        </select>\n\n        <label for=\"choices-multiple-remove-button\">With remove button</label>\n        <select\n          class=\"form-control\"\n          name=\"choices-multiple-remove-button\"\n          id=\"choices-multiple-remove-button\"\n          placeholder=\"This is a placeholder\"\n          multiple\n        >\n          <option value=\"Choice 1\" selected>Choice 1</option>\n          <option value=\"Choice 2\">Choice 2</option>\n          <option value=\"Choice 3\">Choice 3</option>\n          <option value=\"Choice 4\">Choice 4</option>\n        </select>\n\n        <label for=\"choices-multiple-groups\">Option groups</label>\n        <select\n          class=\"form-control\"\n          name=\"choices-multiple-groups\"\n          id=\"choices-multiple-groups\"\n          placeholder=\"This is a placeholder\"\n          multiple\n        >\n          <option value=\"\">Choose a city</option>\n          <optgroup label=\"UK\">\n            <option value=\"London\">London</option>\n            <option value=\"Manchester\">Manchester</option>\n            <option value=\"Liverpool\">Liverpool</option>\n          </optgroup>\n          <optgroup label=\"FR\">\n            <option value=\"Paris\">Paris</option>\n            <option value=\"Lyon\">Lyon</option>\n            <option value=\"Marseille\">Marseille</option>\n          </optgroup>\n          <optgroup label=\"DE\" disabled>\n            <option value=\"Hamburg\">Hamburg</option>\n            <option value=\"Munich\">Munich</option>\n            <option value=\"Berlin\">Berlin</option>\n          </optgroup>\n          <optgroup label=\"US\">\n            <option value=\"New York\">New York</option>\n            <option value=\"Washington\" disabled>Washington</option>\n            <option value=\"Michigan\">Michigan</option>\n          </optgroup>\n          <optgroup label=\"SP\">\n            <option value=\"Madrid\">Madrid</option>\n            <option value=\"Barcelona\">Barcelona</option>\n            <option value=\"Malaga\">Malaga</option>\n          </optgroup>\n          <optgroup label=\"CA\">\n            <option value=\"Montreal\">Montreal</option>\n            <option value=\"Toronto\">Toronto</option>\n            <option value=\"Vancouver\">Vancouver</option>\n          </optgroup>\n        </select>\n\n        <p>\n          <small\n            >If the following example do not load, the Discogs rate limit has\n            probably been reached. Try again later!</small\n          >\n        </p>\n\n        <label for=\"choices-multiple-remote-fetch\"\n          >Options from remote source (Fetch API) &amp; limited to 5</label\n        >\n        <select\n          class=\"form-control\"\n          name=\"choices-multiple-remote-fetch\"\n          id=\"choices-multiple-remote-fetch\"\n          multiple\n        ></select>\n\n        <label for=\"choices-multiple-rtl\">Right-to-left</label>\n        <select\n          class=\"form-control\"\n          data-trigger\n          name=\"choices-multiple-rtl\"\n          id=\"choices-multiple-rtl\"\n          placeholder=\"This is a placeholder\"\n          multiple\n          dir=\"rtl\"\n        >\n          <option value=\"Choice 1\" selected>Choice 1</option>\n          <option value=\"Choice 2\">Choice 2</option>\n          <option value=\"Choice 3\">Choice 3</option>\n          <option value=\"Choice 4\" disabled>Choice 4</option>\n        </select>\n\n        <label for=\"choices-multiple-labels\"\n          >Use label in event (add/remove)</label\n        >\n        <p id=\"message\"></p>\n        <select id=\"choices-multiple-labels\" multiple></select>\n        <hr />\n\n        <h2>Single select input</h2>\n        <label id=\"choices-single-default-label\" for=\"choices-single-default\"\n          >Default</label\n        >\n        <select\n          class=\"form-control\"\n          data-trigger\n          name=\"choices-single-default\"\n          id=\"choices-single-default\"\n          placeholder=\"This is a search placeholder\"\n        >\n          <option value=\"\">This is a placeholder</option>\n          <option value=\"Choice 1\">Choice 1</option>\n          <option value=\"Choice 2\">Choice 2</option>\n          <option value=\"Choice 3\">Choice 3</option>\n        </select>\n\n        <p>\n          <small\n            >If the following two examples do not load, the Discogs rate limit\n            has probably been reached. Try again later!</small\n          >\n        </p>\n\n        <label for=\"choices-single-remote-fetch\"\n          >Options from remote source (Fetch API)</label\n        >\n        <select\n          class=\"form-control\"\n          name=\"choices-single-remote-fetch\"\n          id=\"choices-single-remote-fetch\"\n        >\n          <option value=\"\">Pick an Arctic Monkeys' record</option>\n        </select>\n\n        <label for=\"choices-single-remove-xhr\"\n          >Options from remote source (Fetch API) &amp; remove button</label\n        >\n        <select\n          class=\"form-control\"\n          name=\"choices-single-remove-xhr\"\n          id=\"choices-single-remove-xhr\"\n        >\n          <option value=\"\">Pick a Smiths' record</option>\n        </select>\n\n        <label for=\"choices-single-groups\">Option groups</label>\n        <select\n          class=\"form-control\"\n          data-trigger\n          name=\"choices-single-groups\"\n          id=\"choices-single-groups\"\n        >\n          <option value=\"\">Choose a city</option>\n          <optgroup label=\"UK\">\n            <option value=\"London\">London</option>\n            <option value=\"Manchester\">Manchester</option>\n            <option value=\"Liverpool\">Liverpool</option>\n          </optgroup>\n          <optgroup label=\"FR\">\n            <option value=\"Paris\">Paris</option>\n            <option value=\"Lyon\">Lyon</option>\n            <option value=\"Marseille\">Marseille</option>\n          </optgroup>\n          <optgroup label=\"DE\" disabled>\n            <option value=\"Hamburg\">Hamburg</option>\n            <option value=\"Munich\">Munich</option>\n            <option value=\"Berlin\">Berlin</option>\n          </optgroup>\n          <optgroup label=\"US\">\n            <option value=\"New York\">New York</option>\n            <option value=\"Washington\" disabled>Washington</option>\n            <option value=\"Michigan\">Michigan</option>\n          </optgroup>\n          <optgroup label=\"SP\">\n            <option value=\"Madrid\">Madrid</option>\n            <option value=\"Barcelona\">Barcelona</option>\n            <option value=\"Malaga\">Malaga</option>\n          </optgroup>\n          <optgroup label=\"CA\">\n            <option value=\"Montreal\">Montreal</option>\n            <option value=\"Toronto\">Toronto</option>\n            <option value=\"Vancouver\">Vancouver</option>\n          </optgroup>\n        </select>\n\n        <label for=\"choices-single-rtl\">Right-to-left</label>\n        <select\n          class=\"form-control\"\n          data-trigger\n          name=\"choices-single-rtl\"\n          id=\"choices-single-rtl\"\n          dir=\"rtl\"\n        >\n          <option value=\"Choice 1\">Choice 1</option>\n          <option value=\"Choice 2\">Choice 2</option>\n          <option value=\"Choice 3\">Choice 3</option>\n        </select>\n\n        <label for=\"choices-single-no-search\"\n          >Options added via config with no search</label\n        >\n        <select\n          class=\"form-control\"\n          name=\"choices-single-no-search\"\n          id=\"choices-single-no-search\"\n        >\n          <option value=\"0\">Zero</option>\n        </select>\n\n        <label for=\"choices-single-preset-options\"\n          >Option and option groups added via config</label\n        >\n        <select\n          class=\"form-control\"\n          name=\"choices-single-preset-options\"\n          id=\"choices-single-preset-options\"\n        ></select>\n\n        <label for=\"choices-single-selected-option\"\n          >Option selected via config with custom properties</label\n        >\n        <p>\n          <small>Try searching for 'fantastic', \"Label 3\" should display</small>\n        </p>\n        <select\n          class=\"form-control\"\n          name=\"choices-single-selected-option\"\n          id=\"choices-single-selected-option\"\n        ></select>\n\n        <label for=\"choices-with-custom-props-via-html\"\n          >Option searchable by custom properties via\n          <code>data-custom-properties</code> attribute</label\n        >\n        <p>\n          <small>Try searching for 'fantastic', \"Label 3\" should display</small>\n        </p>\n        <select class=\"form-control\" id=\"choices-with-custom-props-via-html\">\n          <option value=\"Dropdown item 1\">Label One</option>\n          <option value=\"Dropdown item 2\" selected disabled>Label Two</option>\n          <option\n            value=\"Dropdown item 3\"\n            data-custom-properties=\"This option is fantastic\"\n            >Label Three</option\n          >\n          <option\n            value=\"Dropdown item 4\"\n            data-custom-properties=\"{ 'description': 'foo' }\"\n            >Label Four</option\n          >\n        </select>\n\n        <label\n          id=\"choices-single-no-sorting-label\"\n          for=\"choices-single-no-sorting\"\n          >Options without sorting</label\n        >\n        <select\n          class=\"form-control\"\n          name=\"choices-single-no-sorting\"\n          id=\"choices-single-no-sorting\"\n        >\n          <option value=\"Madrid\">Madrid</option>\n          <option value=\"Toronto\">Toronto</option>\n          <option value=\"Vancouver\">Vancouver</option>\n          <option value=\"London\">London</option>\n          <option value=\"Manchester\">Manchester</option>\n          <option value=\"Liverpool\">Liverpool</option>\n          <option value=\"Paris\">Paris</option>\n          <option value=\"Malaga\">Malaga</option>\n          <option value=\"Washington\" disabled>Washington</option>\n          <option value=\"Lyon\">Lyon</option>\n          <option value=\"Marseille\">Marseille</option>\n          <option value=\"Hamburg\">Hamburg</option>\n          <option value=\"Munich\">Munich</option>\n          <option value=\"Barcelona\">Barcelona</option>\n          <option value=\"Berlin\">Berlin</option>\n          <option value=\"Montreal\">Montreal</option>\n          <option value=\"New York\">New York</option>\n          <option value=\"Michigan\">Michigan</option>\n        </select>\n\n        <div data-test-hook=\"custom-templates\">\n        <label for=\"choices-single-custom-templates\">Custom templates</label>\n        <select\n          class=\"form-control\"\n          name=\"choices-single-custom-templates\"\n          id=\"choices-single-custom-templates\"\n        >\n          <option value=\"React\">React</option>\n          <option value=\"Angular\">Angular</option>\n          <option value=\"Ember\">Ember</option>\n          <option value=\"Vue\">Vue</option>\n        </select>\n        </div>\n\n        <p>\n          Below is an example of how you could have two select inputs depend on\n          eachother. 'Tube stations' will only be enabled if the value of\n          'Cities' is 'London'\n        </p>\n        <label for=\"cities\">Cities</label>\n        <select class=\"form-control\" name=\"cities\" id=\"cities\">\n          <option value=\"\">Choose a city</option>\n          <option value=\"Leeds\">Leeds</option>\n          <option value=\"Manchester\">Manchester</option>\n          <option value=\"London\">London</option>\n          <option value=\"Sheffield\">Sheffield</option>\n          <option value=\"Newcastle\">Newcastle</option>\n        </select>\n\n        <label for=\"tube-stations\">Tube stations</label>\n        <select class=\"form-control\" name=\"tube-stations\" id=\"tube-stations\">\n          <option value=\"\">Choose a tube station</option>\n          <option value=\"Moorgate\">Moorgate</option>\n          <option value=\"St Pauls\">St Pauls</option>\n          <option value=\"Old Street\">Old Street</option>\n          <option value=\"Liverpool Street\">Liverpool Street</option>\n          <option value=\"Kings Cross St. Pancras\"\n            >Kings Cross St. Pancras</option\n          >\n        </select>\n\n        <hr />\n        <h2>Form interaction</h2>\n        <p>Change the values and press reset to restore to initial state.</p>\n        <form data-test-hook=\"reset-form\" style=\"margin-bottom:0\">\n          <div data-test-hook=\"reset-simple\">\n          <label for=\"reset-simple\">Change me!</label>\n          <select class=\"form-control\" name=\"reset-simple\" id=\"reset-simple\">\n            <option value=\"Option 1\">Option 1</option>\n            <option value=\"Option 2\" selected>Option 2</option>\n            <option value=\"Option 3\">Option 3</option>\n            <option value=\"Option 4\">Option 4</option>\n            <option value=\"Option 5\">Option 5</option>\n          </select>\n          </div>\n\n          <label for=\"reset-multiple\">And me!</label>\n          <select\n            class=\"form-control\"\n            name=\"reset-multiple\"\n            id=\"reset-multiple\"\n            multiple\n          >\n            <option value=\"Choice 1\" selected>Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\">Choice 3</option>\n            <option value=\"Choice 4\" disabled>Choice 4</option>\n          </select>\n\n          <button type=\"reset\">Reset</button>\n        </form>\n\n        <hr />\n        <h2>Form validation</h2>\n        <p>Try submitting the form first.</p>\n        <p>\n          <small>Then try setting the values as they are required!</small>\n        </p>\n        <form data-test-hook=\"invalid-form\" style=\"margin-bottom:0\">\n          <div data-test-hook=\"invalid-select\">\n            <label for=\"invalid-select\">Change me!</label>\n            <select class=\"form-control\" name=\"reset-simple\" id=\"invalid-select\" required>\n              <option value selected>-</option>\n              <option value=\"Option 1\">Option 1</option>\n              <option value=\"Option 2\">Option 2</option>\n              <option value=\"Option 3\">Option 3</option>\n              <option value=\"Option 4\">Option 4</option>\n              <option value=\"Option 5\">Option 5</option>\n            </select>\n          </div>\n          <div data-test-hook=\"invalid-input\">\n            <label for=\"invalid-input\">And me!</label>\n            <input\n              class=\"form-control\"\n              id=\"invalid-input\"\n              type=\"text\"\n              placeholder=\"Enter something\"\n              required\n            />\n          </div>\n          <button type=\"submit\">Submit</button>\n        </form>\n      </div>\n    </div>\n    <script>\n      document.addEventListener('DOMContentLoaded', function() {\n        var genericExamples = document.querySelectorAll('[data-trigger]');\n        for (i = 0; i < genericExamples.length; ++i) {\n          var element = genericExamples[i];\n          new Choices(element, {\n            allowHTML: true,\n            placeholderValue: 'This is a placeholder set in the config',\n            searchPlaceholderValue: 'This is a search placeholder',\n          });\n        }\n\n        var textRemove = new Choices(\n          document.getElementById('choices-text-remove-button'),\n          {\n            allowHTML: true,\n            delimiter: ',',\n            editItems: true,\n            maxItemCount: 5,\n            removeItemButton: true,\n          }\n        );\n\n        var textUniqueVals = new Choices('#choices-text-unique-values', {\n          allowHTML: true,\n          paste: false,\n          duplicateItemsAllowed: false,\n          editItems: true,\n        });\n\n        var texti18n = new Choices('#choices-text-i18n', {\n          allowHTML: true,\n          paste: false,\n          duplicateItemsAllowed: false,\n          editItems: true,\n          maxItemCount: 5,\n          addItemText: function(value) {\n            return (\n              'Appuyez sur Entrée pour ajouter <b>\"' + String(value) + '\"</b>'\n            );\n          },\n          maxItemText: function(maxItemCount) {\n            return String(maxItemCount) + 'valeurs peuvent être ajoutées';\n          },\n          uniqueItemText: 'Cette valeur est déjà présente',\n        });\n\n        var textEmailFilter = new Choices('#choices-text-email-filter', {\n          allowHTML: true,\n          editItems: true,\n          addItemFilter: function(value) {\n            if (!value) {\n              return false;\n            }\n\n            const regex = /^(([^<>()\\[\\]\\\\.,;:\\s@\"]+(\\.[^<>()\\[\\]\\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$/;\n            const expression = new RegExp(regex.source, 'i');\n            return expression.test(value);\n          },\n        }).setValue(['joe@bloggs.com']);\n\n        var textDisabled = new Choices('#choices-text-disabled', {\n          allowHTML: true,\n          addItems: false,\n          removeItems: false,\n        }).disable();\n\n        var textPrependAppendVal = new Choices(\n          '#choices-text-prepend-append-value',\n          {\n            allowHTML: true,\n            prependValue: 'item-',\n            appendValue: '-' + Date.now(),\n          }\n        ).removeActiveItems();\n\n        var textPresetVal = new Choices('#choices-text-preset-values', {\n          allowHTML: true,\n          items: [\n            'Josh Johnson',\n            {\n              value: 'joe@bloggs.co.uk',\n              label: 'Joe Bloggs',\n              customProperties: {\n                description: 'Joe Blogg is such a generic name',\n              },\n            },\n          ],\n        });\n\n        var multipleDefault = new Choices(\n          document.getElementById('choices-multiple-groups'),\n          { allowHTML: true }\n        );\n\n        var multipleFetch = new Choices('#choices-multiple-remote-fetch', {\n          allowHTML: false,\n          placeholder: true,\n          placeholderValue: 'Pick an Strokes record',\n          maxItemCount: 5,\n        }).setChoices(function() {\n          return fetch(\n            'https://api.discogs.com/artists/55980/releases?token=QBRmstCkwXEvCjTclCpumbtNwvVkEzGAdELXyRyW'\n          )\n            .then(function(response) {\n              return response.json();\n            })\n            .then(function(data) {\n              return data.releases.map(function(release) {\n                return { value: release.title, label: release.title };\n              });\n            });\n        });\n\n        var multipleCancelButton = new Choices(\n          '#choices-multiple-remove-button',\n          {\n            allowHTML: true,\n            removeItemButton: true,\n          }\n        );\n\n        /* Use label on event */\n        var choicesSelect = new Choices('#choices-multiple-labels', {\n          allowHTML: true,\n          removeItemButton: true,\n          choices: [\n            { value: 'One', label: 'Label One' },\n            { value: 'Two', label: 'Label Two', disabled: true },\n            { value: 'Three', label: 'Label Three' },\n          ],\n        }).setChoices(\n          [\n            { value: 'Four', label: 'Label Four', disabled: true },\n            { value: 'Five', label: 'Label Five' },\n            { value: 'Six', label: 'Label Six', selected: true },\n          ],\n          'value',\n          'label',\n          false\n        );\n\n        choicesSelect.passedElement.element.addEventListener(\n          'addItem',\n          function(event) {\n            document.getElementById('message').innerHTML =\n              'You just added \"' + event.detail.label + '\"';\n          }\n        );\n\n        choicesSelect.passedElement.element.addEventListener(\n          'removeItem',\n          function(event) {\n            document.getElementById('message').innerHTML =\n              'You just removed \"' + event.detail.label + '\"';\n          }\n        );\n\n        var singleFetch = new Choices('#choices-single-remote-fetch', {\n          allowHTML: false,\n          searchPlaceholderValue: 'Search for an Arctic Monkeys record',\n        })\n          .setChoices(function() {\n            return fetch(\n              'https://api.discogs.com/artists/391170/releases?token=QBRmstCkwXEvCjTclCpumbtNwvVkEzGAdELXyRyW'\n            )\n              .then(function(response) {\n                return response.json();\n              })\n              .then(function(data) {\n                return data.releases.map(function(release) {\n                  return { label: release.title, value: release.title };\n                });\n              });\n          })\n          .then(function(instance) {\n            instance.setChoiceByValue('Fake Tales Of San Francisco');\n          });\n\n        var singleXhrRemove = new Choices('#choices-single-remove-xhr', {\n          allowHTML: true,\n          removeItemButton: true,\n          searchPlaceholderValue: \"Search for a Smiths' record\",\n        }).setChoices(function(callback) {\n          return fetch(\n            'https://api.discogs.com/artists/83080/releases?token=QBRmstCkwXEvCjTclCpumbtNwvVkEzGAdELXyRyW'\n          )\n            .then(function(res) {\n              return res.json();\n            })\n            .then(function(data) {\n              return data.releases.map(function(release) {\n                return { label: release.title, value: release.title };\n              });\n            });\n        });\n\n        var singleNoSearch = new Choices('#choices-single-no-search', {\n          allowHTML: true,\n          searchEnabled: false,\n            removeItemButton: true,\n          choices: [\n            { value: 'One', label: 'Label One' },\n            { value: 'Two', label: 'Label Two', disabled: true },\n            { value: 'Three', label: 'Label Three' },\n          ],\n        }).setChoices(\n          [\n            { value: 'Four', label: 'Label Four', disabled: true },\n            { value: 'Five', label: 'Label Five' },\n            { value: 'Six', label: 'Label Six', selected: true },\n          ],\n          'value',\n          'label',\n          false\n        );\n\n        var singlePresetOpts = new Choices('#choices-single-preset-options', {\n          allowHTML: true,\n          placeholder: true,\n        }).setChoices(\n          [\n            {\n              label: 'Group one',\n              id: 1,\n              disabled: false,\n              choices: [\n                { value: 'Child One', label: 'Child One', selected: true },\n                { value: 'Child Two', label: 'Child Two', disabled: true },\n                { value: 'Child Three', label: 'Child Three' },\n              ],\n            },\n            {\n              label: 'Group two',\n              id: 2,\n              disabled: false,\n              choices: [\n                { value: 'Child Four', label: 'Child Four', disabled: true },\n                { value: 'Child Five', label: 'Child Five' },\n                { value: 'Child Six', label: 'Child Six' },\n              ],\n            },\n          ],\n          'value',\n          'label'\n        );\n\n        var singleSelectedOpt = new Choices('#choices-single-selected-option', {\n          allowHTML: true,\n          searchFields: ['label', 'value', 'customProperties.description'],\n          choices: [\n            { value: 'One', label: 'Label One', selected: true },\n            { value: 'Two', label: 'Label Two', disabled: true },\n            {\n              value: 'Three',\n              label: 'Label Three',\n              customProperties: {\n                description: 'This option is fantastic',\n              },\n            },\n          ],\n        }).setChoiceByValue('Two');\n\n        var customChoicesPropertiesViaDataAttributes = new Choices(\n          '#choices-with-custom-props-via-html',\n          {\n            allowHTML: true,\n            searchFields: ['label', 'value', 'customProperties'],\n          }\n        );\n\n        var singleNoSorting = new Choices('#choices-single-no-sorting', {\n          allowHTML: true,\n          shouldSort: false,\n          labelId: 'choices-single-no-sorting-label',\n        });\n\n        var cities = new Choices(document.getElementById('cities'), { allowHTML: true });\n        var tubeStations = new Choices(\n          document.getElementById('tube-stations'),\n          { allowHTML: true }\n        ).disable();\n\n        cities.passedElement.element.addEventListener('change', function(e) {\n          if (e.detail.value === 'London') {\n            tubeStations.enable();\n          } else {\n            tubeStations.disable();\n          }\n        });\n\n        var customTemplates = new Choices(\n          document.getElementById('choices-single-custom-templates'),\n          {\n            allowHTML: true,\n            position: 'bottom',\n            callbackOnCreateTemplates: function(strToEl, escapeForTemplate) {\n              var classNames = this.config.classNames;\n              var itemSelectText = this.config.itemSelectText;\n              var allowHTML = this.config.allowHTML;\n              return {\n                item: function({ classNames }, data) {\n                  return strToEl(\n                    '\\\n                <div\\\n                  class=\"' +\n                      String(classNames.item) +\n                      ' ' +\n                      String(\n                        data.highlighted\n                          ? classNames.highlightedState\n                          : classNames.itemSelectable\n                      ) +\n                      '\"\\\n                  data-item\\\n                  role=\"option\"\\\n                  data-id=\"' +\n                      String(data.id) +\n                      '\"\\\n                  data-value=\"' +\n                      String(escapeForTemplate(allowHTML, data.value)) +\n                      '\"\\\n                  ' +\n                      String(data.active ? 'aria-selected=\"true\"' : '') +\n                      '\\\n                  ' +\n                      String(data.disabled ? 'aria-disabled=\"true\"' : '') +\n                      '\\\n                  >\\\n                  <span style=\"margin-right:10px;\">🎉</span> ' +\n                      String(escapeForTemplate(allowHTML, data.label)) +\n                      '\\\n                </div>\\\n              '\n                  );\n                },\n                choice: function({ classNames }, data) {\n                  return strToEl(\n                    '\\\n                <div\\\n                  class=\"' +\n                      String(classNames.item) +\n                      ' ' +\n                      String(classNames.itemChoice) +\n                      ' ' +\n                      String(\n                        data.disabled\n                          ? classNames.itemDisabled\n                          : classNames.itemSelectable\n                      ) +\n                      '\"\\\n                  data-select-text=\"' +\n                      String(itemSelectText) +\n                      '\"\\\n                  data-choice \\\n                  ' +\n                      String(\n                        data.disabled\n                          ? 'data-choice-disabled aria-disabled=\"true\"'\n                          : 'data-choice-selectable'\n                      ) +\n                      '\\\n                  data-id=\"' +\n                      String(data.id) +\n                      '\"\\\n                  data-value=\"' +\n                      String(escapeForTemplate(allowHTML, data.value)) +\n                      '\"\\\n                  ' +\n                      String(\n                        data.groupId > 0 ? 'role=\"treeitem\"' : 'role=\"option\"'\n                      ) +\n                      '\\\n                  >\\\n                  <span style=\"margin-right:10px;\">👉🏽</span> ' +\n                      String(escapeForTemplate(allowHTML, data.label)) +\n                      '\\\n                </div>\\\n              '\n                  );\n                },\n              };\n            },\n          }\n        );\n\n        var resetSimple = new Choices(document.getElementById('reset-simple'), {\n          allowHTML: true,\n        });\n\n        var resetMultiple = new Choices('#reset-multiple', {\n          allowHTML: true,\n          removeItemButton: true,\n        });\n\n        var invalidText = new Choices(\n          document.getElementById('invalid-input'),\n          {\n            allowHTML: true,\n            delimiter: ',',\n            editItems: true,\n            maxItemCount: 5,\n            removeItemButton: true,\n          }\n        );\n\n        var invalidSelect = new Choices(document.getElementById('invalid-select'), {\n          allowHTML: true,\n        });\n      });\n    </script>\n\n    <!-- Google Analytics - Ignore me -->\n    <script>\n      try {\n      window.ga =\n        window.ga ||\n        function() {\n          (ga.q = ga.q || []).push(arguments);\n        };\n      ga.l = +new Date();\n      ga('create', 'UA-31575166-1', 'auto');\n      ga('send', 'pageview');\n      } catch (e) {\n        console.log(e);\n      }\n    </script>\n    <script async src=\"https://www.google-analytics.com/analytics.js\"></script>\n    <!-- End Google Analytics -->\n  </body>\n</html>\n"
  },
  {
    "path": "public/robots.txt",
    "content": "Disallow: /test/*"
  },
  {
    "path": "public/test/data.json",
    "content": "[\n  {\n    \"label\": \"Label 1\",\n    \"value\": \"Value 1\"\n  },\n  {\n    \"label\": \"Label 2\",\n    \"value\": \"Value 2\"\n  },\n  {\n    \"label\": \"Label 3\",\n    \"value\": \"Value 3\"\n  },\n  {\n    \"label\": \"Label 4\",\n    \"value\": \"Value 4\"\n  },\n  {\n    \"label\": \"Label 5\",\n    \"value\": \"Value 5\"\n  },\n  {\n    \"label\": \"Label 6\",\n    \"value\": \"Value 6\"\n  },\n  {\n    \"label\": \"Label 7\",\n    \"value\": \"Value 7\"\n  },\n  {\n    \"label\": \"Label 8\",\n    \"value\": \"Value 8\"\n  },\n  {\n    \"label\": \"Label 9\",\n    \"value\": \"Value 9\"\n  },\n  {\n    \"label\": \"Label 10\",\n    \"value\": \"Value 10\"\n  }\n]"
  },
  {
    "path": "public/test/disabled-data.json",
    "content": "[\n  {\n    \"label\": \"Disabled Label 1\",\n    \"value\": \"Disabled Value 1\",\n    \"disabled\": true\n  },\n  {\n    \"label\": \"Disabled Label 2\",\n    \"value\": \"Disabled Value 2\",\n    \"disabled\": true\n  },\n  {\n    \"label\": \"Disabled Label 3\",\n    \"value\": \"Disabled Value 3\",\n    \"disabled\": true\n  },\n  {\n    \"label\": \"Disabled Label 4\",\n    \"value\": \"Disabled Value 4\",\n    \"disabled\": true\n  },\n  {\n    \"label\": \"Disabled Label 5\",\n    \"value\": \"Disabled Value 5\",\n    \"disabled\": true\n  },\n  {\n    \"label\": \"Disabled Label 6\",\n    \"value\": \"Disabled Value 6\",\n    \"disabled\": true\n  },\n  {\n    \"label\": \"Disabled Label 7\",\n    \"value\": \"Disabled Value 7\",\n    \"disabled\": true\n  },\n  {\n    \"label\": \"Disabled Label 8\",\n    \"value\": \"Disabled Value 8\",\n    \"disabled\": true\n  },\n  {\n    \"label\": \"Disabled Label 9\",\n    \"value\": \"Disabled Value 9\",\n    \"disabled\": true\n  },\n  {\n    \"label\": \"Disabled Label 10\",\n    \"value\": \"Disabled Value 10\",\n    \"disabled\": true\n  }\n]"
  },
  {
    "path": "public/test/select-multiple/index-performance.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta\n      name=\"viewport\"\n      content=\"width=device-width,initial-scale=1,viewport-fit=cover\"\n    />\n    <title>Choices</title>\n    <meta\n      name=\"description\"\n      itemprop=\"description\"\n      content=\"A lightweight, configurable select box/text input plugin. Similar to Select2 and Selectize but without the jQuery dependency.\"\n    />\n    <link\n      rel=\"apple-touch-icon\"\n      sizes=\"180x180\"\n      href=\"../../assets/images/apple-touch-icon.png\"\n    />\n    <link\n      rel=\"icon\"\n      type=\"image/png\"\n      href=\"../../assets/images/favicon-32x32.png\"\n      sizes=\"32x32\"\n    />\n    <link\n      rel=\"icon\"\n      type=\"image/png\"\n      href=\"../../assets/images/favicon-16x16.png\"\n      sizes=\"16x16\"\n    />\n    <link rel=\"manifest\" href=\"../../assets/images/manifest.json\" />\n    <link\n      rel=\"mask-icon\"\n      href=\"../../assets/images/safari-pinned-tab.svg\"\n      color=\"#005F75\"\n    />\n    <link rel=\"shortcut icon\" href=\"../../assets/images/favicon.ico\" />\n    <meta\n      name=\"msapplication-config\"\n      content=\"../../assets/images/browserconfig.xml\"\n    />\n    <meta name=\"theme-color\" content=\"#ffffff\" />\n\n    <!-- Ignore these -->\n    <link rel=\"stylesheet\" href=\"../../assets/styles/base.min.css\" />\n    <!-- End ignore these -->\n\n    <!-- Choices includes -->\n    <link rel=\"stylesheet\" href=\"../../assets/styles/choices.min.css\" />\n    <script src=\"../../assets/scripts/choices.js\"></script>\n    <!-- End Choices includes -->\n  </head>\n\n  <body>\n    <div class=\"container\">\n      <div class=\"section\">\n        <h2>Select multiple inputs</h2>\n        <div data-test-hook=\"basic\">\n          <label for=\"choices-basic\">Basic</label>\n          <button class=\"disable push-bottom\">Disable</button>\n          <button class=\"enable push-bottom\">Enable</button>\n          <button class=\"setChoices push-bottom\">Enable</button>\n          <select\n            class=\"form-control\"\n            name=\"choices-basic\"\n            id=\"choices-basic\"\n            multiple\n          >\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n\n              const options = [...new Array(2000)].map((_, index) => ({\n                selected: !!(index % 2),\n                label: `Choice ${index + 1}$`,\n                value: `Choice ${index + 1}$`,\n              }));\n\n              const choices = new Choices('#choices-basic', {\n                allowHTML: true,\n                shouldSort: false,\n                choices: options,\n              });\n              document\n                .querySelector('button.disable')\n                .addEventListener('click', () => {\n                  choices.disable();\n                });\n\n              document\n                .querySelector('button.enable')\n                .addEventListener('click', () => {\n                  choices.enable();\n                });\n\n              document\n                .querySelector('button.setChoices')\n                .addEventListener('click', () => {\n                  const options = [...new Array(20000)].map((_, index) => ({\n                    selected: !!(index % 2),\n                    label: `Choice ${index + 1}$`,\n                    value: `Choice ${index + 1}$`,\n                  }));\n\n                  choices.setChoices(options, null, null, true);\n                });\n            });\n          </script>\n        </div>\n      </div>\n    </div>\n  </body>\n</html>\n"
  },
  {
    "path": "public/test/select-multiple/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta\n      name=\"viewport\"\n      content=\"width=device-width,initial-scale=1,viewport-fit=cover\"\n    />\n    <title>Choices</title>\n    <meta\n      name=\"description\"\n      itemprop=\"description\"\n      content=\"A lightweight, configurable select box/text input plugin. Similar to Select2 and Selectize but without the jQuery dependency.\"\n    />\n    <link\n      rel=\"apple-touch-icon\"\n      sizes=\"180x180\"\n      href=\"../../assets/images/apple-touch-icon.png\"\n    />\n    <link\n      rel=\"icon\"\n      type=\"image/png\"\n      href=\"../../assets/images/favicon-32x32.png\"\n      sizes=\"32x32\"\n    />\n    <link\n      rel=\"icon\"\n      type=\"image/png\"\n      href=\"../../assets/images/favicon-16x16.png\"\n      sizes=\"16x16\"\n    />\n    <link rel=\"manifest\" href=\"../../assets/images/manifest.json\" />\n    <link\n      rel=\"mask-icon\"\n      href=\"../../assets/images/safari-pinned-tab.svg\"\n      color=\"#005F75\"\n    />\n    <link rel=\"shortcut icon\" href=\"../../assets/images/favicon.ico\" />\n    <meta\n      name=\"msapplication-config\"\n      content=\"../../assets/images/browserconfig.xml\"\n    />\n    <meta name=\"theme-color\" content=\"#ffffff\" />\n\n    <!-- Ignore these -->\n    <link rel=\"stylesheet\" href=\"../../assets/styles/base.min.css\" />\n    <!-- End ignore these -->\n\n    <!-- Choices includes -->\n    <link rel=\"stylesheet\" href=\"../../assets/styles/choices.min.css\" />\n    <script src=\"../../assets/scripts/choices.js\"></script>\n    <!-- End Choices includes -->\n  </head>\n\n  <body>\n    <div class=\"container\">\n      <div class=\"section\">\n        <h2>Select multiple inputs</h2>\n        <div data-test-hook=\"basic\">\n          <label for=\"choices-basic\">Basic</label>\n          <button class=\"disable push-bottom\">Disable</button>\n          <button class=\"enable push-bottom\">Enable</button>\n          <select\n            class=\"form-control\"\n            name=\"choices-basic\"\n            id=\"choices-basic\"\n            multiple\n          >\n            <option value=\"Choice 1\"><!-- html comment -->Choice 1</option>\n            <option value=\"Choice 2\" label=\"Choice 2\" />\n            <option value=\"Find me\">Choice 3</option>\n            <option value=\"Choice 4\">Choice 4</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              const choicesBasic = new Choices('#choices-basic', {\n                allowHTML: false,\n              });\n              document\n                .querySelector('button.disable')\n                .addEventListener('click', () => {\n                  choicesBasic.disable();\n                });\n\n              document\n                .querySelector('button.enable')\n                .addEventListener('click', () => {\n                  choicesBasic.enable();\n                });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"single-item\">\n          <label for=\"choices-basic\">Single-item</label>\n          <select class=\"form-control\" name=\"choices-single-item\" id=\"choices-single-item\">\n            <option value=\"Choice 1\">Choice 1</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-single-item', {\n                allowHTML: true,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"render-selected-choices\">\n          <label for=\"choices-remove-button\">Render selected choices</label>\n          <select\n            class=\"form-control\"\n            name=\"render-selected-choices\"\n            id=\"render-selected-choices\"\n            multiple\n          >\n            <option value=\"Choice 1\" selected>Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\">Choice 3</option>\n            <option value=\"Choice 4\">Choice 4</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#render-selected-choices', {\n                allowHTML: true,\n                renderSelectedChoices: true,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"selected-choice-in-dropdown\">\n          <label for=\"selected-choice-in-dropdown\">Selected choice in dropdown</label>\n          <select\n            class=\"form-control\"\n            name=\"selected-choice-in-dropdown\"\n            id=\"selected-choice-in-dropdown\"\n            multiple\n          >\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\" selected>Choice 3</option>\n            <option value=\"Choice 4\" selected>Choice 4</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#selected-choice-in-dropdown', {\n                allowHTML: true,\n                renderSelectedChoices: true,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"remove-button\">\n          <label for=\"choices-remove-button\">Remove button</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-remove-button\"\n            id=\"choices-remove-button\"\n            multiple\n          >\n            <option value=\"Choice 1\" selected>Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\">Choice 3</option>\n            <option value=\"Choice 4\">Choice 4</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-remove-button', {\n                allowHTML: true,\n                removeItemButton: true,\n              });\n            });\n          </script>\n\n        </div>\n\n        <div data-test-hook=\"no-press-to-select\">\n          <label for=\"no-press-to-select\">No press to select</label>\n          <select\n            class=\"form-control\"\n            name=\"no-press-to-select\"\n            id=\"no-press-to-select\"\n            multiple\n          >\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\">Choice 3</option>\n            <option value=\"Choice 4\">Choice 4</option>\n          </select>\n\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#no-press-to-select', {\n                allowHTML: true,\n                itemSelectText: '',\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"duplicate-items-allowed\">\n          <label for=\"duplicate-items-allowed\">Duplicate items allowed</label>\n          <select class=\"form-control\" name=\"no-choices\" id=\"duplicate-items-allowed\" multiple>\n            <option value=\"call1\">Service 1</option>\n            <option value=\"call2\">Service 2</option>\n            <option value=\"call2\">Service 3</option>\n            <option value=\"call1\">Service 4</option>\n            <option value=\"call5\">Service 5</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#duplicate-items-allowed', {\n                duplicateItemsAllowed: true,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"duplicate-items-disallowed\">\n          <label for=\"duplicate-items-disallowed\">Duplicate items disallowed</label>\n          <select class=\"form-control\" name=\"no-choices\" id=\"duplicate-items-disallowed\" multiple>\n            <option value=\"call1\">Service 1</option>\n            <option value=\"call2\">Service 2</option>\n            <option value=\"call2\">Service 3</option>\n            <option value=\"call1\">Service 4</option>\n            <option value=\"call5\">Service 5</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#duplicate-items-disallowed', {\n                duplicateItemsAllowed: false,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"renderSelectedChoices-true\">\n          <label for=\"renderSelectedChoices-true\">Render selected choices (single option)</label>\n          <select class=\"form-control\" name=\"no-choices\" id=\"renderSelectedChoices-true\" multiple>\n            <option value=\"Choice 1\" selected>Choice 1</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#renderSelectedChoices-true', {\n                renderSelectedChoices: true,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"no-choices\">\n          <label for=\"no-choices\">No choices</label>\n          <select class=\"form-control\" name=\"no-choices\" id=\"no-choices\" multiple>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#no-choices', {\n                allowHTML: true,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"no-choices2\">\n          <label for=\"no-choices2\">No choices (besides selected)</label>\n          <select class=\"form-control\" name=\"no-choices\" id=\"no-choices2\" multiple>\n            <option value=\"Choice 1\" selected=\"selected\">Choice 1</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#no-choices2', {\n                allowHTML: true,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"disabled-choice\">\n          <label for=\"choices-disabled-choice\">Disabled choice</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-disabled-choice\"\n            id=\"choices-disabled-choice\"\n            multiple\n          >\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\">Choice 3</option>\n            <option value=\"Choice 4\" disabled>Choice 4</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-disabled-choice', {\n                allowHTML: true,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"disabled-first-choice-via-options\">\n          <label for=\"choices-disabled-choice-via-options\"\n          >Disabled first choice by options</label\n          >\n          <select\n            class=\"form-control\"\n            name=\"choices-disabled-choice-via-options\"\n            id=\"choices-disabled-choice-via-options\"\n            multiple\n          >\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-disabled-choice-via-options', {\n                allowHTML: true,\n                removeItemButton: true,\n                choices: [\n                  {\n                    value: 'Choice 1',\n                    label: 'Choice 1',\n                    disabled: true,\n                  },\n                  {\n                    value: 'Choice 2',\n                    label: 'Choice 2',\n                  },\n                  {\n                    value: 'Choice 3',\n                    label: 'Choice 3',\n                  },\n                  {\n                    value: 'Choice 4',\n                    label: 'Choice 4',\n                  },\n                ],\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"disabled-via-fieldset\">\n          <fieldset disabled>\n          <label for=\"choices-disabled-via-fieldset\">Disabled via fieldset</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-disabled-via-fieldset\"\n            id=\"choices-disabled-via-fieldset\"\n            multiple\n          >\n            <option value=\"Choice 1\" selected>Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\">Choice 3</option>\n          </select>\n          </fieldset>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-disabled-via-fieldset', {\n                allowHTML: true,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"disabled-via-attr\">\n          <label for=\"choices-disabled-via-attr\">Disabled via attribute</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-disabled-via-attr\"\n            id=\"choices-disabled-via-attr\"\n            multiple\n            disabled\n          >\n            <option value=\"Choice 1\" selected>Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\">Choice 3</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-disabled-via-attr', {\n                allowHTML: true,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"selection-limit\">\n          <label for=\"choices-selection-limit\">Input limit</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-selection-limit\"\n            id=\"choices-selection-limit\"\n            multiple\n          >\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\">Choice 3</option>\n            <option value=\"Choice 4\">Choice 4</option>\n            <option value=\"Choice 5\">Choice 5</option>\n            <option value=\"Choice 6\">Choice 6</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-selection-limit', {\n                allowHTML: true,\n                maxItemCount: 5,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"selection-limit-note-after-unselecting-choice\">\n          <label for=\"choices-selection-limit-note-after-unselecting-choice\">Input limit note after unselecting choice</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-selection-limit-note-after-unselecting-choice\"\n            id=\"choices-selection-limit-note-after-unselecting-choice\"\n            multiple\n          >\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\">Choice 3</option>\n            <option value=\"Choice 4\">Choice 4</option>\n            <option value=\"Choice 5\">Choice 5</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-selection-limit-note-after-unselecting-choice', {\n                allowHTML: true,\n                maxItemCount: 5,\n                removeItemButton: true\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"prepend-append\">\n          <label for=\"choices-prepend-append\">Prepend/append</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-prepend-append\"\n            id=\"choices-prepend-append\"\n            multiple\n          >\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\">Choice 3</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-prepend-append', {\n                allowHTML: true,\n                prependValue: 'before-',\n                appendValue: '-after',\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"render-choice-limit\">\n          <label for=\"choices-render-choice-limit\">Render choice limit</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-render-choice-limit\"\n            id=\"choices-render-choice-limit\"\n            multiple\n          >\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\">Choice 3</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-render-choice-limit', {\n                allowHTML: true,\n                renderChoiceLimit: 1,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"search-disabled\">\n          <label for=\"choices-search-disabled\">Search disabled</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-search-disabled\"\n            id=\"choices-search-disabled\"\n            multiple\n          >\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\">Choice 3</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-search-disabled', {\n                allowHTML: true,\n                searchEnabled: false,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"search-floor\">\n          <label for=\"choices-search-floor\">Search floor</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-search-floor\"\n            id=\"choices-search-floor\"\n            multiple\n          >\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\">Choice 3</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-search-floor', {\n                allowHTML: true,\n                searchFloor: 5,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"search-hide-selected\">\n          <label for=\"choices-search-hide-selected\">Search hide selected</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-search-hide-selected\"\n            id=\"choices-search-hide-selected\"\n            multiple\n          >\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\">Choice 3</option>\n            <option value=\"Choice 4\">Choice 4</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-search-hide-selected', {\n                allowHTML: false,\n                searchRenderSelectedChoices: false,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"placeholder-via-option-value\">\n          <label for=\"choices-placeholder-via-option-value\"\n            >Placeholder via empty option value</label\n          >\n          <select\n            class=\"form-control\"\n            name=\"choices-placeholder-via-option-value\"\n            id=\"choices-placeholder-via-option-value\"\n            multiple\n          >\n            <option value=\"\">I am a placeholder</option>\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\">Choice 3</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-placeholder-via-option-value', {\n                allowHTML: true,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"placeholder-via-option-attr\">\n          <label for=\"choices-placeholder-via-option-attr\"\n            >Placeholder via option attribute</label\n          >\n          <select\n            class=\"form-control\"\n            name=\"choices-placeholder-via-option-attr\"\n            id=\"choices-placeholder-via-option-attr\"\n            multiple\n          >\n            <option placeholder>I am a placeholder</option>\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\">Choice 3</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-placeholder-via-option-attr', {\n                allowHTML: true,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"placeholder-via-data-attr\">\n          <label for=\"choices-placeholder-via-data-attr\"\n          >Placeholder via data attribute</label\n          >\n          <select\n            class=\"form-control\"\n            name=\"choices-placeholder-via-data-attr\"\n            id=\"choices-placeholder-via-data-attr\"\n            data-placeholder=\"I am a placeholder\"\n            multiple\n          >\n            <option value=\"\">I am a not placeholder</option>\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\">Choice 3</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-placeholder-via-data-attr', {\n                allowHTML: true,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"remote-data\">\n          <label for=\"choices-remote-data\">Remote data</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-remote-data\"\n            id=\"choices-remote-data\"\n            multiple\n          >\n            <option value=\"\">I am a placeholder</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-remote-data', {\n                allowHTML: true,\n                shouldSort: false,\n              }).setChoices(async () => {\n                try {\n                  const data = await fetch('../data.json');\n                  return data.json();\n                } catch (e) {\n                  console.log(e);\n                  return [];\n                }\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"scrolling-dropdown\">\n          <label for=\"choices-scrolling-dropdown\">Scrolling dropdown</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-scrolling-dropdown\"\n            id=\"choices-scrolling-dropdown\"\n            multiple\n          >\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\">Choice 3</option>\n            <option value=\"Choice 4\">Choice 4</option>\n            <option value=\"Choice 5\">Choice 5</option>\n            <option value=\"Choice 6\">Choice 6</option>\n            <option value=\"Choice 7\">Choice 7</option>\n            <option value=\"Choice 8\">Choice 8</option>\n            <option value=\"Choice 9\">Choice 9</option>\n            <option value=\"Choice 10\">Choice 10</option>\n            <option value=\"Choice 11\">Choice 11</option>\n            <option value=\"Choice 12\">Choice 12</option>\n            <option value=\"Choice 13\">Choice 13</option>\n            <option value=\"Choice 14\">Choice 14</option>\n            <option value=\"Choice 15\">Choice 15</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-scrolling-dropdown', {\n                allowHTML: true,\n                shouldSort: false,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"groups\">\n          <label for=\"choices-groups\">Choice groups</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-groups\"\n            id=\"choices-groups\"\n            multiple\n          >\n            <optgroup label=\"UK\">\n              <option value=\"London\">London</option>\n              <option value=\"Manchester\">Manchester</option>\n              <option value=\"Liverpool\">Liverpool</option>\n            </optgroup>\n            <optgroup label=\"FR\">\n              <option value=\"Paris\">Paris</option>\n              <option value=\"Lyon\">Lyon</option>\n              <option value=\"Marseille\">Marseille</option>\n            </optgroup>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-groups', {\n                allowHTML: true,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"mixed-groups\">\n          <label for=\"mixed-choices-groups\"\n            >Choice groups with some elements without a group</label\n          >\n          <select\n            class=\"form-control\"\n            name=\"mixed-choices-groups\"\n            id=\"mixed-choices-groups\"\n            multiple\n          >\n            <optgroup label=\"UK\">\n              <option value=\"London\">London</option>\n            </optgroup>\n            <option value=\"Paris\">Paris</option>\n            <option value=\"Lyon\">Lyon</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#mixed-choices-groups', {\n                allowHTML: false,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"custom-properties\">\n          <label for=\"choices-custom-properties\">Custom properties</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-custom-properties\"\n            id=\"choices-custom-properties\"\n            multiple\n          ></select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-custom-properties', {\n                allowHTML: true,\n                searchFields: ['label', 'value', 'customProperties.country'],\n                choices: [\n                  {\n                    id: 1,\n                    value: 'London',\n                    label: 'London',\n                    customProperties: {\n                      country: 'United Kingdom',\n                    },\n                  },\n                  {\n                    id: 2,\n                    value: 'Berlin',\n                    label: 'Berlin',\n                    customProperties: {\n                      country: 'Germany',\n                    },\n                  },\n                  {\n                    id: 3,\n                    value: 'Lisbon',\n                    label: 'Lisbon',\n                    customProperties: {\n                      country: 'Portugal',\n                    },\n                  },\n                ],\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"custom-properties-html\">\n          <label for=\"choices-custom-properties-html\">Custom properties</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-custom-properties-html\"\n            id=\"choices-custom-properties-html\"\n          >\n            <option value=\"Dropdown item 1\">Label One</option>\n            <option value=\"Dropdown item 2\">Label Two</option>\n            <option\n              value=\"Dropdown item 3\"\n              data-custom-properties=\"This option is fantastic\"\n              >Label Three</option\n            >\n            <option\n              value=\"Dropdown item 4\"\n              data-custom-properties=\"{ 'description': 'foo' }\"\n              >Label Four</option\n            >\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-custom-properties-html', {\n                allowHTML: true,\n                searchFields: ['label', 'value', 'customProperties'],\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"non-string-values\">\n          <label for=\"choices-non-string-values\">Non-string values</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-non-string-values\"\n            id=\"choices-non-string-values\"\n          ></select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-non-string-values', {\n                allowHTML: true,\n                choices: [\n                  {\n                    id: 1,\n                    label: 'Number',\n                    value: 1,\n                  },\n                  {\n                    id: 2,\n                    label: 'Boolean',\n                    value: true,\n                  },\n                  {\n                    id: 3,\n                    label: 'Object',\n                    value: {\n                      test: true,\n                    },\n                  },\n                  {\n                    id: 4,\n                    label: 'Array',\n                    value: ['test'],\n                  },\n                ],\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"within-form\">\n          <form>\n            <label for=\"choices-within-form\">Within form</label>\n            <select\n              class=\"form-control\"\n              name=\"choices-within-form\"\n              id=\"choices-within-form\"\n              multiple\n            >\n              <option value=\"Choice 1\">Choice 1</option>\n              <option value=\"Choice 2\">Choice 2</option>\n            </select>\n          </form>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-within-form', {\n                allowHTML: true,\n              });\n            });\n          </script>\n\n        </div>\n\n        <div data-test-hook=\"set-choice-by-value\">\n          <label for=\"choices-set-choice-by-value\"\n            >Dynamically set choice by value</label\n          >\n          <select\n            class=\"form-control\"\n            name=\"choices-set-choice-by-value\"\n            id=\"choices-set-choice-by-value\"\n            multiple\n          >\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\">Choice 3</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-set-choice-by-value', {\n                allowHTML: true,\n              }).setChoiceByValue('Choice 2');\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"search-by-label\">\n          <label for=\"choices-search-by-label\">Search by label</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-search-by-label\"\n            id=\"choices-search-by-label\"\n            multiple\n          >\n            <option value=\"value1\">label1</option>\n            <option value=\"value2\">label2</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-search-by-label', {\n                allowHTML: true,\n                searchFields: ['label']\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"allowhtml-undefined\">\n          <label for=\"choices-allowhtml-undefined\">HTML disabled by default (adds choices)</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-allowhtml-undefined\"\n            id=\"choices-allowhtml-undefined\"\n            multiple\n          ></select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-allowhtml-undefined', {\n                addChoices: true,\n                choices: [\n                  {\n                    id: 1,\n                    label: '<b>Choice 1</b>',\n                    value: 'Choice 1',\n                    selected: true\n                  },\n                  {\n                    id: 2,\n                    label: '<b>Choice 2</b>',\n                    value: 'Choice 2',\n                  },\n                  {\n                    id: 3,\n                    label: 'Choice 3',\n                    value: 'Choice 3',\n                  },\n                ],\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"allowhtml-true\">\n          <label for=\"choices-allowhtml-true\">HTML allowed (adds choices)</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-allowhtml-true\"\n            id=\"choices-allowhtml-true\"\n            multiple\n          ></select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-allowhtml-true', {\n                allowHTML: true,\n                allowHtmlUserInput: true,\n                addChoices: true,\n                choices: [\n                  {\n                    id: 1,\n                    label: '<b>Choice 1</b>',\n                    value: 'Choice 1',\n                    selected: true\n                  },\n                  {\n                    id: 2,\n                    label: '<b>Choice 2</b>',\n                    value: 'Choice 2',\n                  },\n                  {\n                    id: 3,\n                    label: 'Choice 3',\n                    value: 'Choice 3',\n                  },\n                ],\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"allowhtml-true-userinput-false\">\n          <label for=\"choices-allowhtml-true-userinput-false\">HTML allowed (except user input, adds choices)</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-allowhtml-true-userinput-false\"\n            id=\"choices-allowhtml-true-userinput-false\"\n            multiple\n          ></select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-allowhtml-true-userinput-false', {\n                allowHTML: true,\n                allowHtmlUserInput: false,\n                addChoices: true,\n                choices: [\n                  {\n                    id: 1,\n                    label: '<b>Choice 1</b>',\n                    value: 'Choice 1',\n                    selected: true\n                  },\n                  {\n                    id: 2,\n                    label: '<b>Choice 2</b>',\n                    value: 'Choice 2',\n                  },\n                  {\n                    id: 3,\n                    label: 'Choice 3',\n                    value: 'Choice 3',\n                  },\n                ],\n              });\n\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"allowhtml-false\">\n          <label for=\"choices-allowhtml-false\">HTML disabled (adds choices)</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-allowhtml-false\"\n            id=\"choices-allowhtml-false\"\n            multiple\n          ></select>\n\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-allowhtml-false', {\n                allowHTML: false,\n                allowHtmlUserInput: false,\n                addChoices: true,\n                choices: [\n                  {\n                    id: 1,\n                    label: '<b>Choice 1</b>',\n                    value: 'Choice 1',\n                    selected: true\n                  },\n                  {\n                    id: 2,\n                    label: '<b>Choice 2</b>',\n                    value: 'Choice 2',\n                  },\n                  {\n                    id: 3,\n                    label: 'Choice 3',\n                    value: 'Choice 3',\n                  },\n                ],\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"new-destroy-init\">\n          <label for=\"choices-new-destroy-init\">New, Destroy, Init</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-new-destroy-init\"\n            id=\"choices-new-destroy-init\"\n            multiple\n          >\n            <option value=\"Choice 1\">Choice 1</option>\n            <optgroup label=\"test\">\n              <option value=\"Choice 2\">Choice 2</option>\n            </optgroup>\n            <option value=\"Choice 3\">Choice 3</option>\n          </select>\n          <button class=\"destroy\">Destroy</button>\n          <button class=\"init\">Init</button>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              const newDestroyInitChoices = new Choices('#choices-new-destroy-init', {\n                allowHTML: true,\n              });\n              document\n                .querySelector('button.destroy')\n                .addEventListener('click', () => {\n                  newDestroyInitChoices.destroy();\n                });\n              document.querySelector('button.init').addEventListener('click', () => {\n                newDestroyInitChoices.init();\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"shadow-dom\">\n          <noscript style=\"display:none;\">\n          <link rel=\"stylesheet\" href=\"../../assets/styles/base.min.css\" />\n          <link rel=\"stylesheet\" href=\"../../assets/styles/choices.min.css\" />\n          <script src=\"../../assets/scripts/choices.min.js\"></script>\n          <label for=\"shadow-dom-choices-basic\">Shadow DOM - Basic</label>\n          <button class=\"disable push-bottom\">Disable</button>\n          <button class=\"enable push-bottom\">Enable</button>\n          <select\n            class=\"form-control\"\n            name=\"shadow-dom-choices-basic\"\n            id=\"shadow-dom-choices-basic\"\n            multiple\n          >\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Find me\">Choice 3</option>\n            <option value=\"Choice 4\">Choice 4</option>\n          </select>\n          </noscript>\n          <div data-shadow-dom></div>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              const shadowDomTest = document.querySelector('div[data-test-hook=\"shadow-dom\"]'),\n                payload = shadowDomTest.querySelector('noscript'),\n                shadowDomHtml = payload.innerHTML,\n                shadowDomWrapper = shadowDomTest.querySelector('div[data-shadow-dom]');\n              payload.innerHTML = ''; // ensure the shadow-dom example is not part of the main document\n              const shadowRoot = shadowDomWrapper.attachShadow({ mode: 'open' });\n              shadowRoot.innerHTML = shadowDomHtml;\n\n              new Choices('#shadow-dom-choices-basic', {\n                allowHTML: false,\n                shadowRoot: shadowRoot,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"autocomplete\">\n          <label for=\"choices-autocomplete\">Autocomplete example</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-autocomplete\"\n            id=\"choices-autocomplete\"\n            multiple\n          >\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              const choices = new Choices('#choices-autocomplete', {\n                shouldSort: false,\n              });\n              choices.passedElement.element.addEventListener(\n                'search',\n                function(e) {\n                  const query = e.detail.value\n\n                  if (query.length < 2) {\n                    choices.clearChoices()\n                    return\n                  }\n\n                  let result = []\n                  if (query.slice(0, 2) === 'fo') {\n                    result = [{ value: 'found', label: 'Found' }]\n                  }\n\n                  choices.setChoices(\n                    result,\n                    'value',\n                    'label',\n                    true\n                  )\n                }\n              )\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"clear-on-add\">\n          <label for=\"choices-clear-on-add\">Clear choices on add item</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-clear-on-add\"\n            id=\"choices-clear-on-add\"\n            multiple\n          >\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              const choices = new Choices('#choices-clear-on-add', {});\n              choices.passedElement.element.addEventListener(\"addItem\", function () {\n                choices.clearChoices()\n                choices.hideDropdown()\n              })\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"set-choices-preserve\">\n          <label for=\"choices-set-choices-preserve\">setChoices example</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-set-choices-preserve\"\n            id=\"choices-set-choices-preserve\"\n            multiple\n          >\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\" selected>Choice 2</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              const choices = new Choices('#choices-set-choices-preserve', {});\n              choices.setChoices(\n                [\n                  { value: 'Choice 1', label: 'Choice 1' },\n                  { value: 'Choice 2', label: 'Choice 2' }\n                ],\n                'value',\n                'label',\n                true,\n              );\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"set-choices-preserve-no-dupes\">\n          <label for=\"choices-set-choices-preserve\">setChoices example (no duplicates)</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-set-choices-preserve-no-dupes\"\n            id=\"choices-set-choices-preserve-no-dupes\"\n            multiple\n          >\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\" selected>Choice 2</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              const choices = new Choices('#choices-set-choices-preserve-no-dupes', {\n                duplicateItemsAllowed: false,\n              });\n              choices.setChoices(\n                [\n                  { value: 'Choice 1', label: 'Choice 1' },\n                  { value: 'Choice 2', label: 'Choice 2' }\n                ],\n                'value',\n                'label',\n                true,\n              );\n            });\n          </script>\n        </div>\n\n      </div>\n    </div>\n  </body>\n</html>\n"
  },
  {
    "path": "public/test/select-one/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta\n      name=\"viewport\"\n      content=\"width=device-width,initial-scale=1,viewport-fit=cover\"\n    />\n    <title>Choices</title>\n    <meta\n      name=\"description\"\n      itemprop=\"description\"\n      content=\"A lightweight, configurable select box/text input plugin. Similar to Select2 and Selectize but without the jQuery dependency.\"\n    />\n    <link\n      rel=\"apple-touch-icon\"\n      sizes=\"180x180\"\n      href=\"../../assets/images/apple-touch-icon.png\"\n    />\n    <link\n      rel=\"icon\"\n      type=\"image/png\"\n      href=\"../../assets/images/favicon-32x32.png\"\n      sizes=\"32x32\"\n    />\n    <link\n      rel=\"icon\"\n      type=\"image/png\"\n      href=\"../../assets/images/favicon-16x16.png\"\n      sizes=\"16x16\"\n    />\n    <link rel=\"manifest\" href=\"../../assets/images/manifest.json\" />\n    <link\n      rel=\"mask-icon\"\n      href=\"../../assets/images/safari-pinned-tab.svg\"\n      color=\"#005F75\"\n    />\n    <link rel=\"shortcut icon\" href=\"../../assets/images/favicon.ico\" />\n    <meta\n      name=\"msapplication-config\"\n      content=\"../../assets/images/browserconfig.xml\"\n    />\n    <meta name=\"theme-color\" content=\"#ffffff\" />\n\n    <!-- Ignore these -->\n    <link rel=\"stylesheet\" href=\"../../assets/styles/base.min.css\" />\n    <!-- End ignore these -->\n\n    <!-- Choices includes -->\n    <link rel=\"stylesheet\" href=\"../../assets/styles/choices.min.css\" />\n    <script src=\"../../assets/scripts/choices.js\"></script>\n    <!-- End Choices includes -->\n  </head>\n\n  <body>\n    <div class=\"container\">\n      <div class=\"section\">\n        <h2>Select one inputs</h2>\n        <div data-test-hook=\"basic\">\n          <label for=\"choices-basic\">Basic</label>\n          <button class=\"disable push-bottom\">Disable</button>\n          <button class=\"enable push-bottom\">Enable</button>\n          <select class=\"form-control\" name=\"choices-basic\" id=\"choices-basic\">\n            <option value=\"Choice 1\"><!-- html comment -->Choice 1</option>\n            <option value=\"Choice 2\" label=\"Choice 2\" />\n            <option value=\"Find me\">Choice 3</option>\n            <option value=\"Choice 4\">Choice 4</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              const choicesBasic = new Choices('#choices-basic', {\n                allowHTML: false,\n              });\n              document\n                .querySelector('button.disable')\n                .addEventListener('click', () => {\n                  choicesBasic.disable();\n                });\n\n              document\n                .querySelector('button.enable')\n                .addEventListener('click', () => {\n                  choicesBasic.enable();\n                });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"single-item\">\n          <label for=\"choices-basic\">Single-item</label>\n          <select class=\"form-control\" name=\"choices-single-item\" id=\"choices-single-item\">\n            <option value=\"Choice 1\">Choice 1</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-single-item', {\n                allowHTML: true,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"selected-choice-in-dropdown\">\n          <label for=\"selected-choice-in-dropdown\">Selected choice in dropdown</label>\n          <select\n            class=\"form-control\"\n            name=\"selected-choice-in-dropdown\"\n            id=\"selected-choice-in-dropdown\"\n          >\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\" selected>Choice 3</option>\n            <option value=\"Choice 4\">Choice 4</option>\n          </select>\n\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#selected-choice-in-dropdown', {\n                allowHTML: true,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"remove-button\">\n          <label for=\"choices-remove-button\">Remove button</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-remove-button\"\n            id=\"choices-remove-button\"\n          >\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\">Choice 3</option>\n            <option value=\"Choice 4\">Choice 4</option>\n          </select>\n\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-remove-button', {\n                allowHTML: true,\n                removeItemButton: true,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"remove-button-with-sorting-on\">\n          <label for=\"choices-remove-button-with-sorting-on\">Remove button with should sort On</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-remove-button-with-sorting-on\"\n            id=\"choices-remove-button-with-sorting-on\"\n          >\n            <option value=\"Choice 4\" selected>Choice 4</option>\n            <option value=\"Choice 3\">Choice 3</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 1\">Choice 1</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-remove-button-with-sorting-on', {\n                allowHTML: true,\n                removeItemButton: true,\n                shouldSort: true\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"remove-button-with-sorting-off\">\n          <label for=\"choices-remove-button-with-sorting-off\">Remove button with should sort off</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-remove-button-with-sorting-off\"\n            id=\"choices-remove-button-with-sorting-off\"\n          >\n            <option value=\"Choice 4\" selected>Choice 4</option>\n            <option value=\"Choice 3\">Choice 3</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 1\">Choice 1</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-remove-button-with-sorting-off', {\n                allowHTML: true,\n                removeItemButton: true,\n                shouldSort: false\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"no-press-to-select\">\n          <label for=\"no-press-to-select\">No press to select</label>\n          <select\n            class=\"form-control\"\n            name=\"no-press-to-select\"\n            id=\"no-press-to-select\"\n          >\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\">Choice 3</option>\n            <option value=\"Choice 4\">Choice 4</option>\n          </select>\n\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#no-press-to-select', {\n                allowHTML: true,\n                itemSelectText: '',\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"duplicate-items-allowed\">\n          <label for=\"duplicate-items-allowed\">Duplicate items allowed</label>\n          <select class=\"form-control\" name=\"no-choices\" id=\"duplicate-items-allowed\">\n            <option value=\"call1\">Service 1</option>\n            <option value=\"call2\">Service 2</option>\n            <option value=\"call2\">Service 3</option>\n            <option value=\"call1\">Service 4</option>\n            <option value=\"call5\">Service 5</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#duplicate-items-allowed', {\n                duplicateItemsAllowed: true,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"duplicate-items-disallowed\">\n          <label for=\"duplicate-items-disallowed\">Duplicate items disallowed</label>\n          <select class=\"form-control\" name=\"no-choices\" id=\"duplicate-items-disallowed\">\n            <option value=\"call1\">Service 1</option>\n            <option value=\"call2\">Service 2</option>\n            <option value=\"call2\">Service 3</option>\n            <option value=\"call1\">Service 4</option>\n            <option value=\"call5\">Service 5</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#duplicate-items-disallowed', {\n                duplicateItemsAllowed: false,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"renderSelectedChoices-true\">\n          <label for=\"renderSelectedChoices-true\">Render selected choices (single option)</label>\n          <select class=\"form-control\" name=\"no-choices\" id=\"renderSelectedChoices-true\">\n            <option value=\"Choice 1\" selected>Choice 1</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#renderSelectedChoices-true', {\n                renderSelectedChoices: true,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"no-choices\">\n          <label for=\"no-choices\">No choices</label>\n          <select class=\"form-control\" name=\"no-choices\" id=\"no-choices\">\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#no-choices', {\n                allowHTML: true,\n                renderSelectedChoices: false,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"no-choices2\">\n          <label for=\"no-choices2\">No choices (besides selected)</label>\n          <select class=\"form-control\" name=\"no-choices\" id=\"no-choices2\">\n            <option value=\"Choice 1\">Choice 1</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#no-choices2', {\n                allowHTML: true,\n                renderSelectedChoices: false,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"disabled-choice\">\n          <label for=\"choices-disabled-choice\">Disabled choice</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-disabled-choice\"\n            id=\"choices-disabled-choice\"\n          >\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\">Choice 3</option>\n            <option value=\"Choice 4\" disabled>Choice 4</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-disabled-choice', {\n                allowHTML: true,\n                removeItemButton: true,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"disabled-first-choice-via-options\">\n          <label for=\"choices-disabled-choice-via-options\"\n            >Disabled first choice by options</label\n          >\n          <select\n            class=\"form-control\"\n            name=\"choices-disabled-choice-via-options\"\n            id=\"choices-disabled-choice-via-options\"\n          >\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-disabled-choice-via-options', {\n                allowHTML: true,\n                removeItemButton: true,\n                choices: [\n                  {\n                    value: 'Choice 1',\n                    label: 'Choice 1',\n                    disabled: true,\n                  },\n                  {\n                    value: 'Choice 2',\n                    label: 'Choice 2',\n                  },\n                  {\n                    value: 'Choice 3',\n                    label: 'Choice 3',\n                  },\n                  {\n                    value: 'Choice 4',\n                    label: 'Choice 4',\n                  },\n                ],\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"disabled-via-fieldset\">\n          <fieldset disabled>\n          <label for=\"choices-disabled-via-attr\">Disabled via fieldset</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-disabled-via-fieldset\"\n            id=\"choices-disabled-via-fieldset\"\n          >\n            <option value=\"Choice 1\" selected>Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\">Choice 3</option>\n          </select>\n          </fieldset>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-disabled-via-fieldset', {\n                allowHTML: true,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"disabled-via-attr\">\n          <label for=\"choices-disabled-via-attr\">Disabled via attribute</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-disabled-via-attr\"\n            id=\"choices-disabled-via-attr\"\n            disabled\n          >\n            <option value=\"Choice 1\" selected>Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\">Choice 3</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-disabled-via-attr', {\n                allowHTML: true,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"prepend-append\">\n          <label for=\"choices-prepend-append\">Prepend/append</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-prepend-append\"\n            id=\"choices-prepend-append\"\n          >\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\">Choice 3</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-prepend-append', {\n                allowHTML: true,\n                prependValue: 'before-',\n                appendValue: '-after',\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"render-choice-limit\">\n          <label for=\"choices-render-choice-limit\">Render choice limit</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-render-choice-limit\"\n            id=\"choices-render-choice-limit\"\n          >\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\">Choice 3</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-render-choice-limit', {\n                allowHTML: true,\n                renderChoiceLimit: 1,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"search-disabled\">\n          <label for=\"choices-search-disabled\">Search disabled</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-search-disabled\"\n            id=\"choices-search-disabled\"\n          >\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\">Choice 3</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-search-disabled', {\n                allowHTML: true,\n                searchEnabled: false,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"search-floor\">\n          <label for=\"choices-search-floor\">Search floor</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-search-floor\"\n            id=\"choices-search-floor\"\n          >\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\">Choice 3</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-search-floor', {\n                allowHTML: true,\n                searchFloor: 5,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"placeholder-via-option-value\">\n          <label for=\"choices-placeholder-via-option-value\"\n            >Placeholder via empty option value</label\n          >\n          <select\n            class=\"form-control\"\n            name=\"choices-placeholder-via-option-value\"\n            id=\"choices-placeholder-via-option-value\"\n          >\n            <option value=\"\">I am a placeholder</option>\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\">Choice 3</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-placeholder-via-option-value', {\n                allowHTML: true,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"placeholder-via-option-attr\">\n          <label for=\"choices-placeholder-via-option-attr\"\n            >Placeholder via option attribute</label\n          >\n          <select\n            class=\"form-control\"\n            name=\"choices-placeholder-via-option-attr\"\n            id=\"choices-placeholder-via-option-attr\"\n          >\n            <option placeholder>I am a placeholder</option>\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\">Choice 3</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-placeholder-via-option-attr', {\n                allowHTML: true,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"placeholder-via-data-attr\">\n          <label for=\"choices-placeholder-via-data-attr\"\n          >Placeholder via data attribute</label\n          >\n          <select\n            class=\"form-control\"\n            name=\"choices-placeholder-via-data-attr\"\n            id=\"choices-placeholder-via-data-attr\"\n            data-placeholder=\"I am a placeholder\"\n          >\n            <option value=\"\">I am a not placeholder</option>\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\">Choice 3</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-placeholder-via-data-attr', {\n                allowHTML: true,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"remote-data\">\n          <label for=\"choices-remote-data\">Remote data</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-remote-data\"\n            id=\"choices-remote-data\"\n          >\n            <option value=\"\">I am a placeholder</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-remote-data', {\n                allowHTML: true,\n                shouldSort: false,\n              }).setChoices(async () => {\n                try {\n                  const data = await fetch('../data.json');\n                  return data.json();\n                } catch (e) {\n                  console.log(e);\n                  return [];\n                }\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"remote-disabled-data\">\n          <label for=\"choices-remote-disabled-data\">Remote disabled data</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-remote-disabled-data\"\n            id=\"choices-remote-disabled-data\"\n          >\n            <option value=\"\">I am a placeholder</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-remote-disabled-data', {\n                allowHTML: true,\n                shouldSort: false,\n              }).setChoices(async () => {\n                try {\n                  const data = await fetch('../disabled-data.json');\n                  return data.json();\n                } catch (e) {\n                  console.log(e);\n                  return [];\n                }\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"scrolling-dropdown\">\n          <label for=\"choices-scrolling-dropdown\">Scrolling dropdown</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-scrolling-dropdown\"\n            id=\"choices-scrolling-dropdown\"\n          >\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\">Choice 3</option>\n            <option value=\"Choice 4\">Choice 4</option>\n            <option value=\"Choice 5\">Choice 5</option>\n            <option value=\"Choice 6\">Choice 6</option>\n            <option value=\"Choice 7\">Choice 7</option>\n            <option value=\"Choice 8\">Choice 8</option>\n            <option value=\"Choice 9\">Choice 9</option>\n            <option value=\"Choice 10\">Choice 10</option>\n            <option value=\"Choice 11\">Choice 11</option>\n            <option value=\"Choice 12\">Choice 12</option>\n            <option value=\"Choice 13\">Choice 13</option>\n            <option value=\"Choice 14\">Choice 14</option>\n            <option value=\"Choice 15\">Choice 15</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-scrolling-dropdown', {\n                allowHTML: true,\n                shouldSort: false,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"groups\">\n          <label for=\"choices-groups\">Choice groups</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-groups\"\n            id=\"choices-groups\"\n          >\n            <optgroup label=\"UK\">\n              <option value=\"London\">London</option>\n              <option value=\"Manchester\">Manchester</option>\n              <option value=\"Liverpool\">Liverpool</option>\n            </optgroup>\n            <optgroup label=\"FR\">\n              <option value=\"Paris\">Paris</option>\n              <option value=\"Lyon\">Lyon</option>\n              <option value=\"Marseille\">Marseille</option>\n            </optgroup>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-groups', {\n                allowHTML: true,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"mixed-groups\">\n          <label for=\"mixed-choices-groups\"\n          >Choice groups with some elements without a group</label\n          >\n          <select\n            class=\"form-control\"\n            name=\"mixed-choices-groups\"\n            id=\"mixed-choices-groups\"\n          >\n            <optgroup label=\"UK\">\n              <option value=\"London\">London</option>\n            </optgroup>\n            <option value=\"Paris\">Paris</option>\n            <option value=\"Lyon\">Lyon</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#mixed-choices-groups', {\n                allowHTML: false,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"parent-child\">\n          <label for=\"choices-parent\">Parent</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-parent\"\n            id=\"choices-parent\"\n          >\n            <option value=\"Parent choice 1\">Parent choice 1</option>\n            <option value=\"Parent choice 2\">Parent choice 2</option>\n            <option value=\"Parent choice 3\">Parent choice 3</option>\n          </select>\n\n          <label for=\"choices-child\">Child</label>\n          <select class=\"form-control\" name=\"choices-child\" id=\"choices-child\">\n            <option value=\"Child choice 1\">Child choice 1</option>\n            <option value=\"Child choice 2\">Child choice 2</option>\n            <option value=\"Child choice 3\">Child choice 3</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              const parent = new Choices('#choices-parent', {\n                allowHTML: true,\n              });\n              const child = new Choices('#choices-child', {\n                allowHTML: true,\n              }).disable();\n\n              parent.passedElement.element.addEventListener('change', event => {\n                if (event.detail.value === 'Parent choice 2') {\n                  child.enable();\n                } else {\n                  child.disable();\n                }\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"custom-properties\">\n          <label for=\"choices-custom-properties\">Custom properties</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-custom-properties\"\n            id=\"choices-custom-properties\"\n          ></select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-custom-properties', {\n                allowHTML: true,\n                searchFields: ['label', 'value', 'customProperties.country'],\n                choices: [\n                  {\n                    id: 1,\n                    value: 'London',\n                    label: 'London',\n                    customProperties: {\n                      country: 'United Kingdom',\n                    },\n                  },\n                  {\n                    id: 2,\n                    value: 'Berlin',\n                    label: 'Berlin',\n                    customProperties: {\n                      country: 'Germany',\n                    },\n                  },\n                  {\n                    id: 3,\n                    value: 'Lisbon',\n                    label: 'Lisbon',\n                    customProperties: {\n                      country: 'Portugal',\n                    },\n                  },\n                ],\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"custom-properties-html\">\n          <label for=\"choices-custom-properties-html\">Custom properties</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-custom-properties-html\"\n            id=\"choices-custom-properties-html\"\n          >\n            <option value=\"Dropdown item 1\">Label One</option>\n            <option value=\"Dropdown item 2\">Label Two</option>\n            <option\n              value=\"Dropdown item 3\"\n              data-custom-properties=\"This option is fantastic\"\n              >Label Three</option\n            >\n            <option\n              value=\"Dropdown item 4\"\n              data-custom-properties=\"{ 'description': 'foo' }\"\n              >Label Four</option\n            >\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-custom-properties-html', {\n                allowHTML: true,\n                searchFields: ['label', 'value', 'customProperties'],\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"non-string-values\">\n          <label for=\"choices-non-string-values\">Non-string values</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-non-string-values\"\n            id=\"choices-non-string-values\"\n          ></select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-non-string-values', {\n                allowHTML: true,\n                choices: [\n                  {\n                    id: 1,\n                    label: 'Number',\n                    value: 1,\n                  },\n                  {\n                    id: 2,\n                    label: 'Boolean',\n                    value: true,\n                  },\n                  {\n                    id: 3,\n                    label: 'Object',\n                    value: {\n                      test: true,\n                    },\n                  },\n                  {\n                    id: 4,\n                    label: 'Array',\n                    value: ['test'],\n                  },\n                ],\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"within-form\">\n          <form>\n            <label for=\"choices-within-form\">Within form</label>\n            <select\n              class=\"form-control\"\n              name=\"choices-within-form\"\n              id=\"choices-within-form\"\n            >\n              <option value=\"Choice 1\">Choice 1</option>\n              <option value=\"Choice 2\">Choice 2</option>\n            </select>\n          </form>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-within-form', {\n                allowHTML: true,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"set-choice-by-value\">\n          <label for=\"choices-set-choice-by-value\"\n            >Dynamically set choice by value</label\n          >\n          <select\n            class=\"form-control\"\n            name=\"choices-set-choice-by-value\"\n            id=\"choices-set-choice-by-value\"\n          >\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Choice 3\">Choice 3</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-set-choice-by-value', {\n                allowHTML: true,\n              }).setChoiceByValue('Choice 2');\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"search-by-label\">\n          <label for=\"choices-search-by-label\">Search by label</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-search-by-label\"\n            id=\"choices-search-by-label\"\n          >\n            <option value=\"value1\">label1</option>\n            <option value=\"value2\">label2</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-search-by-label', {\n                allowHTML: true,\n                searchFields: ['label']\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"allowhtml-undefined\">\n          <label for=\"choices-allowhtml-undefined\">HTML disabled by default (adds choices)</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-allowhtml-undefined\"\n            id=\"choices-allowhtml-undefined\"\n          ></select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-allowhtml-undefined', {\n                addChoices: true,\n                choices: [\n                  {\n                    id: 1,\n                    label: '<b>Choice 1</b>',\n                    value: 'Choice 1',\n                  },\n                  {\n                    id: 2,\n                    label: 'Choice 2',\n                    value: 'Choice 2',\n                  },\n                ],\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"allowhtml-true\">\n          <label for=\"choices-allowhtml-true\">HTML allowed (adds choices)</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-allowhtml-true\"\n            id=\"choices-allowhtml-true\"\n          ></select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-allowhtml-true', {\n                allowHTML: true,\n                allowHtmlUserInput: true,\n                addChoices: true,\n                choices: [\n                  {\n                    id: 1,\n                    label: '<b>Choice 1</b>',\n                    value: 'Choice 1',\n                  },\n                  {\n                    id: 2,\n                    label: 'Choice 2',\n                    value: 'Choice 2',\n                  },\n                ],\n              });\n\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"allowhtml-true-userinput-false\">\n          <label for=\"choices-allowhtml-true-userinput-false\">HTML allowed (except user input, adds choices)</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-allowhtml-true-userinput-false\"\n            id=\"choices-allowhtml-true-userinput-false\"\n          ></select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-allowhtml-true-userinput-false', {\n                allowHTML: true,\n                allowHtmlUserInput: false,\n                addChoices: true,\n                choices: [\n                  {\n                    id: 1,\n                    label: '<b>Choice 1</b>',\n                    value: 'Choice 1',\n                  },\n                  {\n                    id: 2,\n                    label: 'Choice 2',\n                    value: 'Choice 2',\n                  },\n                ],\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"allowhtml-false\">\n          <label for=\"choices-allowhtml-false\">HTML disabled (adds choices)</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-allowhtml-false\"\n            id=\"choices-allowhtml-false\"\n          ></select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-allowhtml-false', {\n                allowHTML: false,\n                allowHtmlUserInput: false,\n                addChoices: true,\n                choices: [\n                  {\n                    id: 1,\n                    label: '<b>Choice 1</b>',\n                    value: 'Choice 1',\n                  },\n                  {\n                    id: 2,\n                    label: 'Choice 2',\n                    value: 'Choice 2',\n                  },\n                ],\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"new-destroy-init\">\n          <label for=\"choices-new-destroy-init\">New, Destroy, Init</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-new-destroy-init\"\n            id=\"choices-new-destroy-init\"\n          >\n            <option value=\"Choice 1\">Choice 1</option>\n            <optgroup label=\"test\">\n              <option value=\"Choice 2\">Choice 2</option>\n            </optgroup>\n            <option value=\"Choice 3\">Choice 3</option>\n          </select>\n          <button class=\"destroy\">Destroy</button>\n          <button class=\"init\">Init</button>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              const newDestroyInitChoices = new Choices('#choices-new-destroy-init', {\n                allowHTML: true,\n              });\n              document\n                .querySelector('button.destroy')\n                .addEventListener('click', () => {\n                  newDestroyInitChoices.destroy();\n                });\n              document.querySelector('button.init').addEventListener('click', () => {\n                newDestroyInitChoices.init();\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"shadow-dom\">\n          <noscript style=\"display:none;\">\n          <link rel=\"stylesheet\" href=\"../../assets/styles/base.min.css\" />\n          <link rel=\"stylesheet\" href=\"../../assets/styles/choices.min.css\" />\n          <script src=\"../../assets/scripts/choices.min.js\"></script>\n          <label for=\"shadow-dom-choices-basic\">Shadow DOM - Basic</label>\n          <button class=\"disable push-bottom\">Disable</button>\n          <button class=\"enable push-bottom\">Enable</button>\n          <select class=\"form-control\" name=\"shadow-dom-choices-basic\" id=\"shadow-dom-choices-basic\">\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n            <option value=\"Find me\">Choice 3</option>\n            <option value=\"Choice 4\">Choice 4</option>\n          </select>\n          </noscript>\n          <div data-shadow-dom></div>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              const shadowDomTest = document.querySelector('div[data-test-hook=\"shadow-dom\"]'),\n                payload = shadowDomTest.querySelector('noscript'),\n                shadowDomHtml = payload.innerHTML,\n                shadowDomWrapper = shadowDomTest.querySelector('div[data-shadow-dom]');\n              payload.innerHTML = ''; // ensure the shadow-dom example is not part of the main document\n              const shadowRoot = shadowDomWrapper.attachShadow({ mode: 'open' });\n              shadowRoot.innerHTML = shadowDomHtml;\n\n              new Choices('#shadow-dom-choices-basic', {\n                allowHTML: false,\n                shadowRoot: shadowRoot,\n              });\n            });\n          </script>\n      </div>\n\n        <div data-test-hook=\"autocomplete\">\n        <label for=\"choices-autocomplete\">Autocomplete example</label>\n        <select\n          class=\"form-control\"\n          name=\"choices-autocomplete\"\n          id=\"choices-autocomplete\"\n        >\n        </select>\n        <script>\n          document.addEventListener('DOMContentLoaded', function() {\n            const choices = new Choices('#choices-autocomplete', {\n              shouldSort: false,\n              renderSelectedChoices: false,\n            });\n            choices.passedElement.element.addEventListener(\n              'search',\n              function(e) {\n                const query = e.detail.value\n\n                if (query.length < 2) {\n                  choices.clearChoices()\n                  return\n                }\n\n                let result = []\n                if (query.slice(0, 2) === 'fo') {\n                  result = [{ value: 'found', label: 'Found' }]\n                }\n\n                choices.setChoices(\n                  result,\n                  'value',\n                  'label',\n                  true\n                )\n              }\n            )\n          });\n        </script>\n      </div>\n\n        <div data-test-hook=\"clear-on-add\">\n          <label for=\"choices-clear-on-add\">Clear choices on add item</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-clear-on-add\"\n            id=\"choices-clear-on-add\"\n          >\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\">Choice 2</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              const choices = new Choices('#choices-clear-on-add', {});\n              choices.passedElement.element.addEventListener(\"addItem\", function () {\n                choices.clearChoices()\n                choices.hideDropdown()\n              })\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"set-choices-preserve\">\n          <label for=\"choices-set-choices-preserve\">setChoices example</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-set-choices-preserve\"\n            id=\"choices-set-choices-preserve\"\n          >\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\" selected>Choice 2</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              const choices = new Choices('#choices-set-choices-preserve', {});\n              choices.setChoices(\n                [\n                  { value: 'Choice 1', label: 'Choice 1' },\n                  { value: 'Choice 2', label: 'Choice 2' }\n                ],\n                'value',\n                'label',\n                true,\n              );\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"set-choices-preserve-no-dupes\">\n          <label for=\"choices-set-choices-preserve\">setChoices example (no duplicates)</label>\n          <select\n            class=\"form-control\"\n            name=\"choices-set-choices-preserve-no-dupes\"\n            id=\"choices-set-choices-preserve-no-dupes\"\n          >\n            <option value=\"Choice 1\">Choice 1</option>\n            <option value=\"Choice 2\" selected>Choice 2</option>\n          </select>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              const choices = new Choices('#choices-set-choices-preserve-no-dupes', {\n                duplicateItemsAllowed: false,\n              });\n              choices.setChoices(\n                [\n                  { value: 'Choice 1', label: 'Choice 1' },\n                  { value: 'Choice 2', label: 'Choice 2' }\n                ],\n                'value',\n                'label',\n                true,\n              );\n            });\n          </script>\n        </div>\n\n      </div>\n    </div>\n  </body>\n</html>\n"
  },
  {
    "path": "public/test/text/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <meta\n      name=\"viewport\"\n      content=\"width=device-width,initial-scale=1,viewport-fit=cover\"\n    />\n    <title>Choices</title>\n    <meta\n      name=\"description\"\n      itemprop=\"description\"\n      content=\"A lightweight, configurable select box/text input plugin. Similar to Select2 and Selectize but without the jQuery dependency.\"\n    />\n    <link\n      rel=\"apple-touch-icon\"\n      sizes=\"180x180\"\n      href=\"../../assets/images/apple-touch-icon.png\"\n    />\n    <link\n      rel=\"icon\"\n      type=\"image/png\"\n      href=\"../../assets/images/favicon-32x32.png\"\n      sizes=\"32x32\"\n    />\n    <link\n      rel=\"icon\"\n      type=\"image/png\"\n      href=\"../../assets/images/favicon-16x16.png\"\n      sizes=\"16x16\"\n    />\n    <link rel=\"manifest\" href=\"../../assets/images/manifest.json\" />\n    <link\n      rel=\"mask-icon\"\n      href=\"../../assets/images/safari-pinned-tab.svg\"\n      color=\"#005F75\"\n    />\n    <link rel=\"shortcut icon\" href=\"../../assets/images/favicon.ico\" />\n    <meta\n      name=\"msapplication-config\"\n      content=\"../../assets/images/browserconfig.xml\"\n    />\n    <meta name=\"theme-color\" content=\"#ffffff\" />\n\n    <!-- Ignore these -->\n    <link rel=\"stylesheet\" href=\"../../assets/styles/base.min.css\" />\n    <!-- End ignore these -->\n\n    <!-- Choices includes -->\n    <link rel=\"stylesheet\" href=\"../../assets/styles/choices.min.css\" />\n    <script src=\"../../assets/scripts/choices.js\"></script>\n    <!-- End Choices includes -->\n  </head>\n\n  <body>\n    <div class=\"container\">\n      <div class=\"section\">\n        <h2>Text inputs</h2>\n        <div data-test-hook=\"basic\">\n          <label for=\"choices-basic\">Basic</label>\n          <input class=\"form-control\" id=\"choices-basic\" type=\"text\" />\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-basic', {\n                allowHTML: true,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"edit-items\">\n          <label for=\"choices-edit-items\">Edit items</label>\n          <input class=\"form-control\" id=\"choices-edit-items\" type=\"text\" />\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-edit-items', {\n                allowHTML: true,\n                editItems: true,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"remove-button\">\n          <label for=\"choices-remove-button\">Remove button</label>\n          <input class=\"form-control\" id=\"choices-remove-button\" type=\"text\" />\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-remove-button', {\n                allowHTML: true,\n                removeItemButton: true,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"unique-values\">\n          <label for=\"choices-unique-values\">Unique values</label>\n          <input class=\"form-control\" id=\"choices-unique-values\" type=\"text\" />\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-unique-values', {\n                allowHTML: true,\n                duplicateItemsAllowed: false,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"allowhtml-undefined\">\n          <label for=\"allowhtml-undefined\">HTML disabled by default</label>\n          <input class=\"form-control\" id=\"allowhtml-undefined\" type=\"text\" />\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#allowhtml-undefined', {\n                items: [\n                  '<b>Mason Rogers</b>'\n                ],\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"allowhtml-true\">\n          <label for=\"allowhtml-true\">HTML allowed (adds choices)</label>\n          <input class=\"form-control\" id=\"allowhtml-true\" type=\"text\" />\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#allowhtml-true', {\n                allowHTML: true,\n                allowHtmlUserInput: true,\n                items: [\n                  '<b>Mason Rogers</b>'\n                ],\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"allowhtml-true-userinput-false\">\n          <label for=\"allowhtml-true-userinput-false\">HTML allowed (except user input, adds choices)</label>\n          <input class=\"form-control\" id=\"allowhtml-true-userinput-false\" type=\"text\" />\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#allowhtml-true-userinput-false', {\n                allowHTML: true,\n                allowHtmlUserInput: false,\n                items: [\n                  '<b>Mason Rogers</b>'\n                ],\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"allowhtml-false\">\n          <label for=\"allowhtml-false\">HTML disabled (adds choices)</label>\n          <input class=\"form-control\" id=\"allowhtml-false\" type=\"text\" />\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#allowhtml-false', {\n                allowHTML: false,\n                allowHtmlUserInput: false,\n                items: [\n                  '<b>Mason Rogers</b>'\n                ],\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"input-limit\">\n          <label for=\"choices-input-limit\">Input limit</label>\n          <input class=\"form-control\" id=\"choices-input-limit\" type=\"text\" />\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-input-limit', {\n                allowHTML: true,\n                maxItemCount: 5,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"add-item-filter\">\n          <label for=\"choices-add-item-filter\">Add item filter</label>\n          <input\n            class=\"form-control\"\n            id=\"choices-add-item-filter\"\n            type=\"text\"\n          />\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-add-item-filter', {\n                allowHTML: true,\n                addItems: true,\n                addItemFilter: value => {\n                  const regex = /^(([^<>()\\[\\]\\\\.,;:\\s@\"]+(\\.[^<>()\\[\\]\\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$/;\n                  const expression = new RegExp(regex.source, 'i');\n                  return expression.test(value);\n                },\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"adding-items-disabled\">\n          <label for=\"choices-adding-items-disabled\">Add items disabled</label>\n          <input\n            class=\"form-control\"\n            id=\"choices-adding-items-disabled\"\n            type=\"text\"\n          />\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-adding-items-disabled', {\n                allowHTML: true,\n                addItems: false,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"disabled-via-fieldset\">\n          <label for=\"choices-disabled-via-fieldset\">Disabled via fieldset</label>\n          <fieldset disabled>\n            <input\n              class=\"form-control\"\n              id=\"choices-disabled-via-fieldset\"\n              type=\"text\"\n            />\n          </fieldset>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-disabled-via-fieldset', {\n                allowHTML: true,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"disabled-via-attr\">\n          <label for=\"choices-disabled-via-attr\">Disabled via attribute</label>\n          <input\n            class=\"form-control\"\n            id=\"choices-disabled-via-attr\"\n            type=\"text\"\n            disabled\n          />\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-disabled-via-attr', {\n                allowHTML: true,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"prepend-append\">\n          <label for=\"choices-prepend-append\">Prepend/append</label>\n          <input class=\"form-control\" id=\"choices-prepend-append\" type=\"text\" />\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-prepend-append', {\n                allowHTML: true,\n                prependValue: 'before-',\n                appendValue: '-after',\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"prepopulated\">\n          <label for=\"choices-prepopulated\">Pre-populated choices</label>\n          <input class=\"form-control\" id=\"choices-prepopulated\" type=\"text\" />\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-prepopulated', {\n                allowHTML: true,\n                items: [\n                  'Josh Johnson',\n                  {\n                    value: 'joe@bloggs.co.uk',\n                    label: 'Joe Bloggs',\n                    customProperties: {\n                      description: 'Joe Blogg is such a generic name',\n                    },\n                  },\n                ],\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"placeholder\">\n          <label for=\"choices-placeholder\">Placeholder</label>\n          <input class=\"form-control\" id=\"choices-placeholder\" type=\"text\" />\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-placeholder', {\n                allowHTML: true,\n                placeholder: true,\n                placeholderValue: 'I am a placeholder',\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"within-form\">\n          <form>\n            <label for=\"choices-within-form\">Within form</label>\n            <input class=\"form-control\" id=\"choices-within-form\" type=\"text\" />\n          </form>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              new Choices('#choices-within-form', {\n                allowHTML: true,\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"new-destroy-init\">\n          <label for=\"choices-new-destroy-init\">New, Destroy, Init</label>\n          <input class=\"form-control\" id=\"choices-new-destroy-init\" type=\"text\" />\n          <button class=\"destroy\">Destroy</button>\n          <button class=\"init\">Init</button>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              const newDestroyInitChoices = new Choices('#choices-new-destroy-init', {\n                allowHTML: true,\n              });\n              document\n                .querySelector('button.destroy')\n                .addEventListener('click', () => {\n                  newDestroyInitChoices.destroy();\n                });\n              document.querySelector('button.init').addEventListener('click', () => {\n                newDestroyInitChoices.init();\n              });\n            });\n          </script>\n        </div>\n\n        <div data-test-hook=\"shadow-dom\">\n          <noscript style=\"display:none;\">\n          <link rel=\"stylesheet\" href=\"../../assets/styles/base.min.css\" />\n          <link rel=\"stylesheet\" href=\"../../assets/styles/choices.min.css\" />\n          <script src=\"../../assets/scripts/choices.min.js\"></script>\n          <label for=\"shadow-dom-choices-basic\">Shadow DOM - Basic</label>\n          <input class=\"form-control\" id=\"shadow-dom-choices-basic\" type=\"text\" />\n          </noscript>\n          <div data-shadow-dom></div>\n          <script>\n            document.addEventListener('DOMContentLoaded', function() {\n              const shadowDomTest = document.querySelector('div[data-test-hook=\"shadow-dom\"]'),\n                payload = shadowDomTest.querySelector('noscript'),\n                shadowDomHtml = payload.innerHTML,\n                shadowDomWrapper = shadowDomTest.querySelector('div[data-shadow-dom]');\n              payload.innerHTML = ''; // ensure the shadow-dom example is not part of the main document\n              const shadowRoot = shadowDomWrapper.attachShadow({ mode: 'open' });\n              shadowRoot.innerHTML = shadowDomHtml;\n\n              new Choices('#shadow-dom-choices-basic', {\n                allowHTML: false,\n                shadowRoot: shadowRoot,\n              });\n            });\n          </script>\n        </div>\n\n      </div>\n    </div>\n  </body>\n</html>\n"
  },
  {
    "path": "public/types/src/index.d.ts",
    "content": "import Choices from './scripts/choices';\nexport * from './scripts/interfaces';\nexport * from './scripts/constants';\nexport * from './scripts/defaults';\nexport { default as templates } from './scripts/templates';\nexport default Choices;\n"
  },
  {
    "path": "public/types/src/scripts/actions/choices.d.ts",
    "content": "import { ChoiceFull } from '../interfaces/choice-full';\nimport { ActionType } from '../interfaces';\nimport { SearchResult } from '../interfaces/search';\nimport { AnyAction } from '../interfaces/store';\nexport type ChoiceActions = AddChoiceAction | RemoveChoiceAction | FilterChoicesAction | ActivateChoicesAction | ClearChoicesAction;\nexport interface AddChoiceAction extends AnyAction<typeof ActionType.ADD_CHOICE> {\n    choice: ChoiceFull;\n}\nexport interface RemoveChoiceAction extends AnyAction<typeof ActionType.REMOVE_CHOICE> {\n    choice: ChoiceFull;\n}\nexport interface FilterChoicesAction extends AnyAction<typeof ActionType.FILTER_CHOICES> {\n    results: SearchResult<ChoiceFull>[];\n}\nexport interface ActivateChoicesAction extends AnyAction<typeof ActionType.ACTIVATE_CHOICES> {\n    active: boolean;\n}\n/**\n * @deprecated use clearStore() or clearChoices() instead.\n */\nexport interface ClearChoicesAction extends AnyAction<typeof ActionType.CLEAR_CHOICES> {\n}\nexport declare const addChoice: (choice: ChoiceFull) => AddChoiceAction;\nexport declare const removeChoice: (choice: ChoiceFull) => RemoveChoiceAction;\nexport declare const filterChoices: (results: SearchResult<ChoiceFull>[]) => FilterChoicesAction;\nexport declare const activateChoices: (active?: boolean) => ActivateChoicesAction;\n/**\n * @deprecated use clearStore() or clearChoices() instead.\n */\nexport declare const clearChoices: () => ClearChoicesAction;\n"
  },
  {
    "path": "public/types/src/scripts/actions/groups.d.ts",
    "content": "import { GroupFull } from '../interfaces/group-full';\nimport { ActionType } from '../interfaces';\nimport { AnyAction } from '../interfaces/store';\nexport type GroupActions = AddGroupAction;\nexport interface AddGroupAction extends AnyAction<typeof ActionType.ADD_GROUP> {\n    group: GroupFull;\n}\nexport declare const addGroup: (group: GroupFull) => AddGroupAction;\n"
  },
  {
    "path": "public/types/src/scripts/actions/items.d.ts",
    "content": "import { ChoiceFull } from '../interfaces/choice-full';\nimport { ActionType } from '../interfaces';\nimport { AnyAction } from '../interfaces/store';\nexport type ItemActions = AddItemAction | RemoveItemAction | HighlightItemAction;\nexport interface AddItemAction extends AnyAction<typeof ActionType.ADD_ITEM> {\n    item: ChoiceFull;\n}\nexport interface RemoveItemAction extends AnyAction<typeof ActionType.REMOVE_ITEM> {\n    item: ChoiceFull;\n}\nexport interface HighlightItemAction extends AnyAction<typeof ActionType.HIGHLIGHT_ITEM> {\n    item: ChoiceFull;\n    highlighted: boolean;\n}\nexport declare const addItem: (item: ChoiceFull) => AddItemAction;\nexport declare const removeItem: (item: ChoiceFull) => RemoveItemAction;\nexport declare const highlightItem: (item: ChoiceFull, highlighted: boolean) => HighlightItemAction;\n"
  },
  {
    "path": "public/types/src/scripts/choices.d.ts",
    "content": "import { Container, Dropdown, Input, List, WrappedInput, WrappedSelect } from './components';\nimport { InputChoice } from './interfaces/input-choice';\nimport { InputGroup } from './interfaces/input-group';\nimport { Options } from './interfaces/options';\nimport { StateChangeSet } from './interfaces/state';\nimport Store from './store/store';\nimport { ChoiceFull } from './interfaces/choice-full';\nimport { GroupFull } from './interfaces/group-full';\nimport { EventChoiceValueType, PassedElementType } from './interfaces';\nimport { EventChoice } from './interfaces/event-choice';\nimport { NoticeType, Templates } from './interfaces/templates';\nimport { Searcher } from './interfaces/search';\n/**\n * Choices\n * @author Josh Johnson<josh@joshuajohnson.co.uk>\n */\ndeclare class Choices {\n    static version: string;\n    static get defaults(): {\n        options: Partial<Options>;\n        allOptions: Options;\n        templates: Templates;\n    };\n    initialised: boolean;\n    initialisedOK?: boolean;\n    config: Options;\n    passedElement: WrappedInput | WrappedSelect;\n    containerOuter: Container;\n    containerInner: Container;\n    choiceList: List;\n    itemList: List;\n    input: Input;\n    dropdown: Dropdown;\n    _elementType: PassedElementType;\n    _isTextElement: boolean;\n    _isSelectOneElement: boolean;\n    _isSelectMultipleElement: boolean;\n    _isSelectElement: boolean;\n    _hasNonChoicePlaceholder: boolean;\n    _canAddUserChoices: boolean;\n    _store: Store<Options>;\n    _templates: Templates;\n    _lastAddedChoiceId: number;\n    _lastAddedGroupId: number;\n    _currentValue: string;\n    _canSearch: boolean;\n    _isScrollingOnIe: boolean;\n    _highlightPosition: number;\n    _wasTap: boolean;\n    _isSearching: boolean;\n    _placeholderValue: string | null;\n    _baseId: string;\n    _direction: HTMLElement['dir'];\n    _idNames: {\n        itemChoice: string;\n    };\n    _presetChoices: (ChoiceFull | GroupFull)[];\n    _initialItems: string[];\n    _searcher: Searcher<ChoiceFull>;\n    _notice?: {\n        type: NoticeType;\n        text: string;\n    };\n    _docRoot: ShadowRoot | HTMLElement;\n    constructor(element?: string | Element | HTMLInputElement | HTMLSelectElement, userConfig?: Partial<Options>);\n    init(): void;\n    destroy(): void;\n    enable(): this;\n    disable(): this;\n    highlightItem(item: InputChoice, runEvent?: boolean): this;\n    unhighlightItem(item: InputChoice, runEvent?: boolean): this;\n    highlightAll(): this;\n    unhighlightAll(): this;\n    removeActiveItemsByValue(value: string): this;\n    removeActiveItems(excludedId?: number): this;\n    removeHighlightedItems(runEvent?: boolean): this;\n    showDropdown(preventInputFocus?: boolean): this;\n    hideDropdown(preventInputBlur?: boolean): this;\n    getValue<B extends boolean = false>(valueOnly?: B): EventChoiceValueType<B> | EventChoiceValueType<B>[];\n    setValue(items: string[] | InputChoice[]): this;\n    setChoiceByValue(value: string | string[]): this;\n    /**\n     * Set choices of select input via an array of objects (or function that returns array of object or promise of it),\n     * a value field name and a label field name.\n     * This behaves the same as passing items via the choices option but can be called after initialising Choices.\n     * This can also be used to add groups of choices (see example 2); Optionally pass a true `replaceChoices` value to remove any existing choices.\n     * Optionally pass a `customProperties` object to add additional data to your choices (useful when searching/filtering etc).\n     *\n     * **Input types affected:** select-one, select-multiple\n     *\n     * @example\n     * ```js\n     * const example = new Choices(element);\n     *\n     * example.setChoices([\n     *   {value: 'One', label: 'Label One', disabled: true},\n     *   {value: 'Two', label: 'Label Two', selected: true},\n     *   {value: 'Three', label: 'Label Three'},\n     * ], 'value', 'label', false);\n     * ```\n     *\n     * @example\n     * ```js\n     * const example = new Choices(element);\n     *\n     * example.setChoices(async () => {\n     *   try {\n     *      const items = await fetch('/items');\n     *      return items.json()\n     *   } catch(err) {\n     *      console.error(err)\n     *   }\n     * });\n     * ```\n     *\n     * @example\n     * ```js\n     * const example = new Choices(element);\n     *\n     * example.setChoices([{\n     *   label: 'Group one',\n     *   id: 1,\n     *   disabled: false,\n     *   choices: [\n     *     {value: 'Child One', label: 'Child One', selected: true},\n     *     {value: 'Child Two', label: 'Child Two',  disabled: true},\n     *     {value: 'Child Three', label: 'Child Three'},\n     *   ]\n     * },\n     * {\n     *   label: 'Group two',\n     *   id: 2,\n     *   disabled: false,\n     *   choices: [\n     *     {value: 'Child Four', label: 'Child Four', disabled: true},\n     *     {value: 'Child Five', label: 'Child Five'},\n     *     {value: 'Child Six', label: 'Child Six', customProperties: {\n     *       description: 'Custom description about child six',\n     *       random: 'Another random custom property'\n     *     }},\n     *   ]\n     * }], 'value', 'label', false);\n     * ```\n     */\n    setChoices(choicesArrayOrFetcher?: (InputChoice | InputGroup)[] | ((instance: Choices) => (InputChoice | InputGroup)[] | Promise<(InputChoice | InputGroup)[]>), value?: string | null, label?: string, replaceChoices?: boolean, clearSearchFlag?: boolean, replaceItems?: boolean): this | Promise<this>;\n    refresh(withEvents?: boolean, selectFirstOption?: boolean, deselectAll?: boolean): this;\n    removeChoice(value: string): this;\n    clearChoices(clearOptions?: boolean, clearItems?: boolean): this;\n    clearStore(clearOptions?: boolean): this;\n    clearInput(): this;\n    _validateConfig(): void;\n    _render(changes?: StateChangeSet): void;\n    _renderChoices(): void;\n    _renderItems(): void;\n    _displayNotice(text: string, type: NoticeType, openDropdown?: boolean): void;\n    _clearNotice(): void;\n    _renderNotice(fragment?: DocumentFragment): void;\n    /**\n     * @deprecated Use utils.getChoiceForOutput\n     */\n    _getChoiceForOutput(choice: ChoiceFull, keyCode?: number): EventChoice;\n    _triggerChange(value: any): void;\n    _handleButtonAction(element: HTMLElement): void;\n    _handleItemAction(element: HTMLElement, hasShiftKey?: boolean): void;\n    _handleChoiceAction(element: HTMLElement): boolean;\n    _handleBackspace(items: ChoiceFull[]): void;\n    _loadChoices(): void;\n    _handleLoadingState(setLoading?: boolean): void;\n    _handleSearch(value?: string): void;\n    _canAddItems(): boolean;\n    _canCreateItem(value: string): boolean;\n    _searchChoices(value: string): number | null;\n    _stopSearch(): void;\n    _addEventListeners(): void;\n    _removeEventListeners(): void;\n    _onKeyDown(event: KeyboardEvent): void;\n    _onKeyUp(): void;\n    _onInput(): void;\n    _onSelectKey(event: KeyboardEvent, hasItems: boolean): void;\n    _onEnterKey(event: KeyboardEvent, hasActiveDropdown: boolean): void;\n    _onEscapeKey(event: KeyboardEvent, hasActiveDropdown: boolean): void;\n    _onDirectionKey(event: KeyboardEvent, hasActiveDropdown: boolean): void;\n    _onDeleteKey(event: KeyboardEvent, items: ChoiceFull[], hasFocusedInput: boolean): void;\n    _onTouchMove(): void;\n    _onTouchEnd(event: TouchEvent): void;\n    /**\n     * Handles mousedown event in capture mode for containetOuter.element\n     */\n    _onMouseDown(event: MouseEvent): void;\n    /**\n     * Handles mouseover event over this.dropdown\n     * @param {MouseEvent} event\n     */\n    _onMouseOver({ target }: Pick<MouseEvent, 'target'>): void;\n    _onClick({ target }: Pick<MouseEvent, 'target'>): void;\n    _onFocus({ target }: Pick<FocusEvent, 'target'>): void;\n    _onBlur({ target }: Pick<FocusEvent, 'target'>): void;\n    _onFormReset(): void;\n    _onChange(event: Event & {\n        target: HTMLInputElement | HTMLSelectElement;\n    }): void;\n    _onInvalid(): void;\n    /**\n     * Removes any highlighted choice options\n     */\n    _removeHighlightedChoices(): void;\n    _highlightChoice(el?: HTMLElement | null): void;\n    _addItem(item: ChoiceFull, withEvents?: boolean, userTriggered?: boolean): void;\n    _removeItem(item: ChoiceFull): void;\n    _addChoice(choice: ChoiceFull, withEvents?: boolean, userTriggered?: boolean): void;\n    _addGroup(group: GroupFull, withEvents?: boolean): void;\n    _createTemplates(): void;\n    _createElements(): void;\n    _createStructure(): void;\n    _initStore(): void;\n    _addPredefinedChoices(choices: (ChoiceFull | GroupFull)[], selectFirstOption?: boolean, withEvents?: boolean): void;\n    _findAndSelectChoiceByValue(value: string, userTriggered?: boolean): boolean;\n    _generatePlaceholderValue(): string | null;\n    _warnChoicesInitFailed(caller: string): void;\n}\nexport default Choices;\n"
  },
  {
    "path": "public/types/src/scripts/components/container.d.ts",
    "content": "import { ClassNames } from '../interfaces/class-names';\nimport { PositionOptionsType } from '../interfaces/position-options-type';\nimport { PassedElementType } from '../interfaces/passed-element-type';\nexport default class Container {\n    element: HTMLElement;\n    type: PassedElementType;\n    classNames: ClassNames;\n    position: PositionOptionsType;\n    isOpen: boolean;\n    isFlipped: boolean;\n    isDisabled: boolean;\n    isLoading: boolean;\n    constructor({ element, type, classNames, position, }: {\n        element: HTMLElement;\n        type: PassedElementType;\n        classNames: ClassNames;\n        position: PositionOptionsType;\n    });\n    /**\n     * Determine whether container should be flipped based on passed\n     * dropdown position\n     */\n    shouldFlip(dropdownPos: number, dropdownHeight: number): boolean;\n    setActiveDescendant(activeDescendantID: string): void;\n    removeActiveDescendant(): void;\n    open(dropdownPos: number, dropdownHeight: number): void;\n    close(): void;\n    addFocusState(): void;\n    removeFocusState(): void;\n    addInvalidState(): void;\n    removeInvalidState(): void;\n    enable(): void;\n    disable(): void;\n    wrap(element: HTMLElement): void;\n    unwrap(element: HTMLElement): void;\n    addLoadingState(): void;\n    removeLoadingState(): void;\n}\n"
  },
  {
    "path": "public/types/src/scripts/components/dropdown.d.ts",
    "content": "import { ClassNames } from '../interfaces/class-names';\nimport { PassedElementType } from '../interfaces/passed-element-type';\nexport default class Dropdown {\n    element: HTMLElement;\n    type: PassedElementType;\n    classNames: ClassNames;\n    isActive: boolean;\n    constructor({ element, type, classNames, }: {\n        element: HTMLElement;\n        type: PassedElementType;\n        classNames: ClassNames;\n    });\n    /**\n     * Show dropdown to user by adding active state class\n     */\n    show(): this;\n    /**\n     * Hide dropdown from user\n     */\n    hide(): this;\n}\n"
  },
  {
    "path": "public/types/src/scripts/components/index.d.ts",
    "content": "import Dropdown from './dropdown';\nimport Container from './container';\nimport Input from './input';\nimport List from './list';\nimport WrappedInput from './wrapped-input';\nimport WrappedSelect from './wrapped-select';\nexport { Dropdown, Container, Input, List, WrappedInput, WrappedSelect };\n"
  },
  {
    "path": "public/types/src/scripts/components/input.d.ts",
    "content": "import { ClassNames } from '../interfaces/class-names';\nimport { PassedElementType } from '../interfaces/passed-element-type';\nexport default class Input {\n    element: HTMLInputElement;\n    type: PassedElementType;\n    classNames: ClassNames;\n    preventPaste: boolean;\n    isFocussed: boolean;\n    isDisabled: boolean;\n    constructor({ element, type, classNames, preventPaste, }: {\n        element: HTMLInputElement;\n        type: PassedElementType;\n        classNames: ClassNames;\n        preventPaste: boolean;\n    });\n    set placeholder(placeholder: string);\n    get value(): string;\n    set value(value: string);\n    addEventListeners(): void;\n    removeEventListeners(): void;\n    enable(): void;\n    disable(): void;\n    focus(): void;\n    blur(): void;\n    clear(setWidth?: boolean): this;\n    /**\n     * Set the correct input width based on placeholder\n     * value or input value\n     */\n    setWidth(): void;\n    setActiveDescendant(activeDescendantID: string): void;\n    removeActiveDescendant(): void;\n    _onInput(): void;\n    _onPaste(event: ClipboardEvent): void;\n    _onFocus(): void;\n    _onBlur(): void;\n}\n"
  },
  {
    "path": "public/types/src/scripts/components/list.d.ts",
    "content": "export default class List {\n    element: HTMLElement;\n    scrollPos: number;\n    height: number;\n    constructor({ element }: {\n        element: HTMLElement;\n    });\n    prepend(node: Element | DocumentFragment): void;\n    scrollToTop(): void;\n    scrollToChildElement(element: HTMLElement, direction: 1 | -1): void;\n    _scrollDown(scrollPos: number, strength: number, destination: number): void;\n    _scrollUp(scrollPos: number, strength: number, destination: number): void;\n    _animateScroll(destination: number, direction: number): void;\n}\n"
  },
  {
    "path": "public/types/src/scripts/components/wrapped-element.d.ts",
    "content": "import { ClassNames } from '../interfaces/class-names';\nimport { EventTypes } from '../interfaces/event-type';\nimport { EventMap } from '../interfaces';\nexport default class WrappedElement<T extends HTMLInputElement | HTMLSelectElement> {\n    element: T;\n    classNames: ClassNames;\n    isDisabled: boolean;\n    constructor({ element, classNames }: {\n        element: any;\n        classNames: any;\n    });\n    get isActive(): boolean;\n    get dir(): string;\n    get value(): string;\n    set value(value: string);\n    conceal(): void;\n    reveal(): void;\n    enable(): void;\n    disable(): void;\n    triggerEvent<K extends EventTypes>(eventType: EventTypes, data?: EventMap[K]['detail']): void;\n}\n"
  },
  {
    "path": "public/types/src/scripts/components/wrapped-input.d.ts",
    "content": "import WrappedElement from './wrapped-element';\nexport default class WrappedInput extends WrappedElement<HTMLInputElement> {\n}\n"
  },
  {
    "path": "public/types/src/scripts/components/wrapped-select.d.ts",
    "content": "import { ClassNames } from '../interfaces/class-names';\nimport WrappedElement from './wrapped-element';\nimport { GroupFull } from '../interfaces/group-full';\nimport { ChoiceFull } from '../interfaces/choice-full';\nexport default class WrappedSelect extends WrappedElement<HTMLSelectElement> {\n    classNames: ClassNames;\n    template: (data: object) => HTMLOptionElement;\n    extractPlaceholder: boolean;\n    constructor({ element, classNames, template, extractPlaceholder, }: {\n        element: HTMLSelectElement;\n        classNames: ClassNames;\n        template: (data: object) => HTMLOptionElement;\n        extractPlaceholder: boolean;\n    });\n    get placeholderOption(): HTMLOptionElement | null;\n    addOptions(choices: ChoiceFull[]): void;\n    optionsAsChoices(): (ChoiceFull | GroupFull)[];\n    _optionToChoice(option: HTMLOptionElement): ChoiceFull;\n    _optgroupToChoice(optgroup: HTMLOptGroupElement): GroupFull;\n}\n"
  },
  {
    "path": "public/types/src/scripts/constants.d.ts",
    "content": "export declare const SCROLLING_SPEED: number;\n"
  },
  {
    "path": "public/types/src/scripts/defaults.d.ts",
    "content": "import { ClassNames } from './interfaces/class-names';\nimport { Options } from './interfaces/options';\nexport declare const DEFAULT_CLASSNAMES: ClassNames;\nexport declare const DEFAULT_CONFIG: Options;\n"
  },
  {
    "path": "public/types/src/scripts/interfaces/action-type.d.ts",
    "content": "import { Types } from './types';\nexport declare const ActionType: {\n    readonly ADD_CHOICE: \"ADD_CHOICE\";\n    readonly REMOVE_CHOICE: \"REMOVE_CHOICE\";\n    readonly FILTER_CHOICES: \"FILTER_CHOICES\";\n    readonly ACTIVATE_CHOICES: \"ACTIVATE_CHOICES\";\n    readonly CLEAR_CHOICES: \"CLEAR_CHOICES\";\n    readonly ADD_GROUP: \"ADD_GROUP\";\n    readonly ADD_ITEM: \"ADD_ITEM\";\n    readonly REMOVE_ITEM: \"REMOVE_ITEM\";\n    readonly HIGHLIGHT_ITEM: \"HIGHLIGHT_ITEM\";\n};\nexport type ActionTypes = Types.ValueOf<typeof ActionType>;\n"
  },
  {
    "path": "public/types/src/scripts/interfaces/build-flags.d.ts",
    "content": "export declare const canUseDom: boolean;\nexport declare const searchFuse: string | undefined;\nexport declare const searchKMP: boolean;\n/**\n * These are not directly used, as an exported object (even as const) will prevent tree-shake away code paths\n */\nexport declare const BuildFlags: {\n    readonly searchFuse: string | undefined;\n    readonly searchKMP: boolean;\n    readonly canUseDom: boolean;\n};\n"
  },
  {
    "path": "public/types/src/scripts/interfaces/choice-full.d.ts",
    "content": "import { StringUntrusted } from './string-untrusted';\nimport { StringPreEscaped } from './string-pre-escaped';\nimport { Types } from './types';\nimport { GroupFull } from './group-full';\nexport interface ChoiceFull {\n    id: number;\n    highlighted: boolean;\n    element?: HTMLOptionElement | HTMLOptGroupElement;\n    itemEl?: HTMLElement;\n    choiceEl?: HTMLElement;\n    labelClass?: Array<string>;\n    labelDescription?: StringPreEscaped | StringUntrusted | string;\n    customProperties?: Types.CustomProperties;\n    disabled: boolean;\n    active: boolean;\n    elementId?: string;\n    group: GroupFull | null;\n    label: StringUntrusted | string;\n    placeholder: boolean;\n    selected: boolean;\n    value: string;\n    score: number;\n    rank: number;\n}\n"
  },
  {
    "path": "public/types/src/scripts/interfaces/class-names.d.ts",
    "content": "/** Classes added to HTML generated by  By default classnames follow the BEM notation. */\nexport interface ClassNames {\n    /** @default ['choices'] */\n    containerOuter: string | Array<string>;\n    /** @default ['choices__inner'] */\n    containerInner: string | Array<string>;\n    /** @default ['choices__input'] */\n    input: string | Array<string>;\n    /** @default ['choices__input--cloned'] */\n    inputCloned: string | Array<string>;\n    /** @default ['choices__list'] */\n    list: string | Array<string>;\n    /** @default ['choices__list--multiple'] */\n    listItems: string | Array<string>;\n    /** @default ['choices__list--single'] */\n    listSingle: string | Array<string>;\n    /** @default ['choices__list--dropdown'] */\n    listDropdown: string | Array<string>;\n    /** @default ['choices__item'] */\n    item: string | Array<string>;\n    /** @default ['choices__item--selectable'] */\n    itemSelectable: string | Array<string>;\n    /** @default ['choices__item--disabled'] */\n    itemDisabled: string | Array<string>;\n    /** @default ['choices__item--choice'] */\n    itemChoice: string | Array<string>;\n    /** @default ['choices__description'] */\n    description: string | Array<string>;\n    /** @default ['choices__placeholder'] */\n    placeholder: string | Array<string>;\n    /** @default ['choices__group'] */\n    group: string | Array<string>;\n    /** @default ['choices__heading'] */\n    groupHeading: string | Array<string>;\n    /** @default ['choices__button'] */\n    button: string | Array<string>;\n    /** @default ['is-active'] */\n    activeState: string | Array<string>;\n    /** @default ['is-focused'] */\n    focusState: string | Array<string>;\n    /** @default ['is-open'] */\n    openState: string | Array<string>;\n    /** @default ['is-disabled'] */\n    disabledState: string | Array<string>;\n    /** @default ['is-highlighted'] */\n    highlightedState: string | Array<string>;\n    /** @default ['is-selected'] */\n    selectedState: string | Array<string>;\n    /** @default ['is-flipped'] */\n    flippedState: string | Array<string>;\n    /** @default ['is-loading'] */\n    loadingState: string | Array<string>;\n    /** @default ['is-invalid'] */\n    invalidState: string | Array<string>;\n    /** @default ['choices__notice'] */\n    notice: string | Array<string>;\n    /** @default ['choices__item--selectable', 'add-choice'] */\n    addChoice: string | Array<string>;\n    /** @default ['has-no-results'] */\n    noResults: string | Array<string>;\n    /** @default ['has-no-choices'] */\n    noChoices: string | Array<string>;\n}\n"
  },
  {
    "path": "public/types/src/scripts/interfaces/event-choice.d.ts",
    "content": "import { InputChoice } from './input-choice';\nexport type EventChoiceValueType<B extends boolean> = B extends true ? string : EventChoice;\nexport interface EventChoice extends InputChoice {\n    element?: HTMLOptionElement | HTMLOptGroupElement;\n    groupValue?: string;\n    keyCode?: number;\n}\n"
  },
  {
    "path": "public/types/src/scripts/interfaces/event-type.d.ts",
    "content": "import { Types } from './types';\nexport declare const EventType: {\n    readonly showDropdown: \"showDropdown\";\n    readonly hideDropdown: \"hideDropdown\";\n    readonly change: \"change\";\n    readonly choice: \"choice\";\n    readonly search: \"search\";\n    readonly addItem: \"addItem\";\n    readonly removeItem: \"removeItem\";\n    readonly highlightItem: \"highlightItem\";\n    readonly highlightChoice: \"highlightChoice\";\n    readonly unhighlightItem: \"unhighlightItem\";\n};\nexport type EventTypes = Types.ValueOf<typeof EventType>;\n"
  },
  {
    "path": "public/types/src/scripts/interfaces/group-full.d.ts",
    "content": "import { ChoiceFull } from './choice-full';\nexport interface GroupFull {\n    id: number;\n    active: boolean;\n    disabled: boolean;\n    label?: string;\n    element?: HTMLOptGroupElement;\n    groupEl?: HTMLElement;\n    choices: ChoiceFull[];\n}\n"
  },
  {
    "path": "public/types/src/scripts/interfaces/index.d.ts",
    "content": "export * from './action-type';\nexport * from './input-choice';\nexport * from './input-group';\nexport * from './event-choice';\nexport * from './class-names';\nexport * from './event-type';\nexport * from './item';\nexport * from './keycode-map';\nexport * from './options';\nexport * from './passed-element';\nexport * from './passed-element-type';\nexport * from './position-options-type';\nexport * from './state';\nexport * from './types';\n"
  },
  {
    "path": "public/types/src/scripts/interfaces/input-choice.d.ts",
    "content": "import { StringUntrusted } from './string-untrusted';\nimport { StringPreEscaped } from './string-pre-escaped';\nimport { Types } from './types';\nexport interface InputChoice {\n    id?: number;\n    highlighted?: boolean;\n    labelClass?: string | Array<string>;\n    labelDescription?: StringPreEscaped | StringUntrusted | string;\n    customProperties?: Types.CustomProperties;\n    disabled?: boolean;\n    active?: boolean;\n    label: StringUntrusted | string;\n    placeholder?: boolean;\n    selected?: boolean;\n    value: any;\n}\n"
  },
  {
    "path": "public/types/src/scripts/interfaces/input-group.d.ts",
    "content": "import { InputChoice } from './input-choice';\nimport { StringUntrusted } from './string-untrusted';\nexport interface InputGroup {\n    id?: number;\n    active?: boolean;\n    disabled?: boolean;\n    label?: StringUntrusted | string;\n    value: string;\n    choices: InputChoice[];\n}\n"
  },
  {
    "path": "public/types/src/scripts/interfaces/item.d.ts",
    "content": "import { InputChoice } from './input-choice';\nimport { InputGroup } from './input-group';\n/**\n * @deprecated Use InputChoice instead\n */\nexport interface Item extends InputChoice {\n}\n/**\n * @deprecated Use InputChoice instead\n */\nexport interface Choice extends InputChoice {\n}\n/**\n * @deprecated Use InputGroup instead\n */\nexport interface Group extends InputGroup {\n}\n"
  },
  {
    "path": "public/types/src/scripts/interfaces/keycode-map.d.ts",
    "content": "export declare const KeyCodeMap: {\n    readonly TAB_KEY: 9;\n    readonly SHIFT_KEY: 16;\n    readonly BACK_KEY: 46;\n    readonly DELETE_KEY: 8;\n    readonly ENTER_KEY: 13;\n    readonly A_KEY: 65;\n    readonly ESC_KEY: 27;\n    readonly UP_KEY: 38;\n    readonly DOWN_KEY: 40;\n    readonly PAGE_UP_KEY: 33;\n    readonly PAGE_DOWN_KEY: 34;\n};\n"
  },
  {
    "path": "public/types/src/scripts/interfaces/options.d.ts",
    "content": "import { IFuseOptions } from 'fuse.js';\nimport { InputChoice } from './input-choice';\nimport { ClassNames } from './class-names';\nimport { PositionOptionsType } from './position-options-type';\nimport { Types } from './types';\nimport { CallbackOnCreateTemplatesFn } from './templates';\nexport declare const ObjectsInConfig: string[];\n/**\n * Choices options interface\n *\n * **Terminology**\n *\n * - **Choice:** A choice is a value a user can select. A choice would be equivalent to the `<option></option>` element within a select input.\n * - **Group:** A group is a collection of choices. A group should be seen as equivalent to a `<optgroup></optgroup>` element within a select input.\n * - **Item:** An item is an inputted value **_(text input)_** or a selected choice **_(select element)_**. In the context of a select element, an item is equivelent to a selected option element: `<option value=\"Hello\" selected></option>` whereas in the context of a text input an item is equivelant to `<input type=\"text\" value=\"Hello\">`\n */\nexport interface Options {\n    /**\n     * Optionally suppress console errors and warnings.\n     *\n     * **Input types affected:** text, select-single, select-multiple\n     *\n     * @default false\n     */\n    silent: boolean;\n    /**\n     * Add pre-selected items (see terminology) to text input.\n     *\n     * **Input types affected:** text\n     *\n     * @example\n     * ```\n     * ['value 1', 'value 2', 'value 3']\n     * ```\n     *\n     * @example\n     * ```\n     * [{\n     *    value: 'Value 1',\n     *    label: 'Label 1',\n     *    id: 1\n     *  },\n     *  {\n     *    value: 'Value 2',\n     *    label: 'Label 2',\n     *    id: 2,\n     *    customProperties: {\n     *      random: 'I am a custom property'\n     *  }\n     * }]\n     * ```\n     *\n     * @default []\n     */\n    items: string[] | InputChoice[];\n    /**\n     * Add choices (see terminology) to select input.\n     *\n     * **Input types affected:** select-one, select-multiple\n     *\n     * @example\n     * ```\n     * [{\n     *   value: 'Option 1',\n     *   label: 'Option 1',\n     *   selected: true,\n     *   disabled: false,\n     * },\n     * {\n     *   value: 'Option 2',\n     *   label: 'Option 2',\n     *   selected: false,\n     *   disabled: true,\n     *   customProperties: {\n     *     description: 'Custom description about Option 2',\n     *     random: 'Another random custom property'\n     *   },\n     * },\n     * {\n     *   label: 'Group 1',\n     *   choices: [{\n     *     value: 'Option 3',\n     *     label: 'Option 4',\n     *     selected: true,\n     *     disabled: false,\n     *   },\n     *   {\n     *     value: 'Option 2',\n     *     label: 'Option 2',\n     *     selected: false,\n     *     disabled: true,\n     *     customProperties: {\n     *       description: 'Custom description about Option 2',\n     *       random: 'Another random custom property'\n     *     }\n     *   }]\n     * }]\n     * ```\n     *\n     * @default []\n     */\n    choices: InputChoice[];\n    /**\n     * The amount of choices to be rendered within the dropdown list `(\"-1\" indicates no limit)`. This is useful if you have a lot of choices where it is easier for a user to use the search area to find a choice.\n     *\n     * **Input types affected:** select-one, select-multiple\n     *\n     * @default -1\n     */\n    renderChoiceLimit: number;\n    /**\n     * The amount of items a user can input/select `(\"-1\" indicates no limit)`.\n     *\n     * **Input types affected:** text, select-multiple\n     *\n     * @default -1\n     */\n    maxItemCount: number;\n    /**\n     * Control how the dropdown closes after making a selection for select-one or select-multiple\n     *\n     * 'auto' defaults based on backing-element type:\n     * select-one: true\n     * select-multiple: false\n     *\n     * **Input types affected:** select-one, select-multiple\n     *\n     * @default 'auto'\n     */\n    closeDropdownOnSelect: boolean | 'auto';\n    /**\n     * Make select-multiple with a max item count of 1 work similar to select-one does.\n     * Selecting an item will auto-close the dropdown and swap any existing item for the just selected choice.\n     * If applied to a select-one, it functions as above and not the standard select-one.\n     *\n     * **Input types affected:** select-one, select-multiple\n     *\n     * @default false\n     */\n    singleModeForMultiSelect: boolean;\n    /**\n     * Whether a user can add choices dynamically.\n     *\n     * **Input types affected:** select-one, select-multiple\n     *\n     * @default false\n     */\n    addChoices: boolean;\n    /**\n     * Whether a user can add items.\n     *\n     * **Input types affected:** text\n     *\n     * @default true\n     */\n    addItems: boolean;\n    /**\n     * A filter that will need to pass for a user to successfully add an item.\n     *\n     * **Input types affected:** text, select-one, select-multiple\n     *\n     * @default (value) => !!value && value !== ''\n     */\n    addItemFilter: string | RegExp | Types.FilterFunction | null;\n    /**\n     * The text that is shown when a user has inputted a new item but has not pressed the enter key. To access the current input value, pass a function with a `value` argument (see the **default config** [https://github.com/jshjohnson/Choices#setup] for an example), otherwise pass a string.\n     * The raw non-sanitised value is passed as a 2nd argument.\n     *\n     * Return type must be safe to insert into HTML (ie use the 1st argument which is sanitised)\n     *\n     * **Input types affected:** text, one-select, select-one, select-multiple\n     *\n     * @default\n     * ```\n     * (value, valueRaw) => `Press Enter to add <b>\"${value}\"</b>`;\n     * ```\n     */\n    addItemText: string | Types.NoticeStringFunction;\n    /**\n     * The text/icon for the remove button. To access the item's value, pass a function with a `value` argument (see the **default config** [https://github.com/jshjohnson/Choices#setup] for an example), otherwise pass a string.\n     * The raw non-sanitised value is passed as a 2nd argument.\n     *\n     * Return type must be safe to insert into HTML (ie use the 1st argument which is sanitised)\n     *\n     * **Input types affected:** text, select-one, select-multiple\n     *\n     * @default\n     * ```\n     * (value, valueRaw, item) => `Remove item`;\n     * ```\n     */\n    removeItemIconText: string | Types.NoticeStringFunction;\n    /**\n     * The text for the remove button's aria label. To access the item's value, pass a function with a `value` argument (see the **default config** [https://github.com/jshjohnson/Choices#setup] for an example), otherwise pass a string.\n     * The raw non-sanitised value is passed as a 2nd argument.\n     *\n     * Return type must be safe to insert into HTML (ie use the 1st argument which is sanitised)\n     *\n     * **Input types affected:** text, select-one, select-multiple\n     *\n     * @default\n     * ```\n     * (value, valueRaw, item) => `Remove item: ${value}`;\n     * ```\n     */\n    removeItemLabelText: string | Types.NoticeStringFunction;\n    /**\n     * Whether a user can remove items.\n     *\n     * **Input types affected:** text, select-multiple\n     *\n     * @default true\n     */\n    removeItems: boolean;\n    /**\n     * Whether each item should have a remove button.\n     *\n     * **Input types affected:** text, select-one, select-multiple\n     *\n     * @default false\n     */\n    removeItemButton: boolean;\n    /**\n     * Align item remove button left vs right.\n     *\n     * **Input types affected:** text, select-one, select-multiple\n     *\n     * @default false\n     */\n    removeItemButtonAlignLeft: boolean;\n    /**\n     * Whether a user can edit items. An item's value can be edited by pressing the backspace.\n     *\n     * **Input types affected:** text\n     *\n     * @default false\n     */\n    editItems: boolean;\n    /**\n     * Whether HTML should be rendered in all Choices elements.\n     * If `false`, all elements (placeholder, items, etc.) will be treated as plain text.\n     * If `true`, this can be used to perform XSS scripting attacks if you load choices from a remote source.\n     *\n     * **Input types affected:** text, select-one, select-multiple\n     *\n     * @default false\n     */\n    allowHTML: boolean;\n    /**\n     * Whether HTML should be escaped on input when `addItems` or `addChoices` is true.\n     * If `false`, user input will be treated as plain text.\n     * If `true`, this can be used to perform XSS scripting attacks if you load previously submitted choices from a remote source.\n     *\n     * **Input types affected:** text, select-one, select-multiple\n     *\n     * @default false\n     */\n    allowHtmlUserInput: boolean;\n    /**\n     * Whether each inputted/chosen item should be unique.\n     *\n     * **Input types affected:** text, `select-multiple`, `select-one`\n     *\n     * @default true\n     */\n    duplicateItemsAllowed: boolean;\n    /**\n     * What divides each value. The default delimiter separates each value with a comma: `\"Value 1, Value 2, Value 3\"`.\n     *\n     * **Input types affected:** text\n     *\n     * @default ','\n     */\n    delimiter: string;\n    /**\n     * Whether a user can paste into the input.\n     *\n     * **Input types affected:** text, select-multiple\n     *\n     * @default true\n     */\n    paste: boolean;\n    /**\n     * Whether a search area should be shown.\n     *\n     * **Input types affected:** select-one, select-multiple\n     *\n     * @default true\n     */\n    searchEnabled: boolean;\n    /**\n     * Whether choices should be filtered by input or not. If `false`, the search event will still emit, but choices will not be filtered.\n     *\n     * **Input types affected:** select-one\n     *\n     * @default true\n     */\n    searchChoices: boolean;\n    /**\n     * Whether disabled choices should be included in search results. If `true`, disabled choices will appear in search results but still cannot be selected.\n     *\n     * **Input types affected:** select-one, select-multiple\n     *\n     * @default false\n     */\n    searchDisabledChoices: boolean;\n    /**\n     * The minimum length a search value should be before choices are searched.\n     *\n     * **Input types affected:** select-one, select-multiple\n     *\n     * @default 1\n     */\n    searchFloor: number;\n    /**\n     * The maximum amount of search results to show. `(\"-1\" indicates no limit)`\n     *\n     * **Input types affected:** select-one, select-multiple\n     *\n     * @default 4\n     */\n    searchResultLimit: number;\n    /**\n     * Specify which fields should be used when a user is searching. If you have added custom properties to your choices, you can add these values thus: `['label', 'value', 'customProperties.example']`.\n     *\n     * Input types affected:select-one, select-multiple\n     *\n     * @default ['label', 'value']\n     */\n    searchFields: string[];\n    /**\n     * Whether the dropdown should appear above `(top)` or below `(bottom)` the input. By default, if there is not enough space within the window the dropdown will appear above the input, otherwise below it.\n     *\n     * **Input types affected:** select-one, select-multiple\n     *\n     * @default 'auto'\n     */\n    position: PositionOptionsType;\n    /**\n     * Whether the scroll position should reset after adding an item.\n     *\n     * **Input types affected:** select-multiple\n     *\n     * @default true\n     */\n    resetScrollPosition: boolean;\n    /**\n     * The shadow root for use within ShadowDom\n     */\n    shadowRoot: ShadowRoot | null;\n    /**\n     * Whether choices and groups should be sorted. If false, choices/groups will appear in the order they were given.\n     *\n     * **Input types affected:** select-one, select-multiple\n     *\n     * @default true\n     */\n    shouldSort: boolean;\n    /**\n     * Whether items should be sorted. If false, items will appear in the order they were selected.\n     *\n     * **Input types affected:** text, select-multiple\n     *\n     * @default false\n     */\n    shouldSortItems: boolean;\n    /**\n     * The function that will sort choices and items before they are displayed (unless a user is searching). By default choices and items are sorted by alphabetical order.\n     *\n     * **Input types affected:** select-one, select-multiple\n     *\n     * @example\n     * ```\n     * // Sorting via length of label from largest to smallest\n     * const example = new Choices(element, {\n     *   sorter: function(a, b) {\n     *     return b.label.length - a.label.length;\n     *   },\n     * };\n     * ```\n     *\n     * @default sortByAlpha\n     */\n    sorter: (current: Types.RecordToCompare, next: Types.RecordToCompare) => number;\n    /**\n     * Whether the input should show a placeholder. Used in conjunction with `placeholderValue`. If `placeholder` is set to true and no value is passed to `placeholderValue`, the passed input's placeholder attribute will be used as the placeholder value.\n     *\n     * **Input types affected:** text, select-multiple\n     *\n     * @note For single select boxes, the recommended way of adding a placeholder is as follows:\n     * ```\n     * <select data-placeholder=\"This is a placeholder\">\n     *   <option>...</option>\n     *   <option>...</option>\n     *   <option>...</option>\n     * </select>\n     * ```\n     *\n     * @default true\n     */\n    placeholder: boolean;\n    /**\n     * The value of the inputs placeholder.\n     *\n     * **Input types affected:** text, select-multiple\n     *\n     * @default null\n     */\n    placeholderValue: string | null;\n    /**\n     * The value of the search inputs placeholder.\n     *\n     * **Input types affected:** select-one\n     *\n     * @default null\n     */\n    searchPlaceholderValue: string | null;\n    /**\n     * Prepend a value to each item added/selected.\n     *\n     * **Input types affected:** text, select-one, select-multiple\n     *\n     * @default null\n     */\n    prependValue: string | null;\n    /**\n     * Append a value to each item added/selected.\n     *\n     * **Input types affected:** text, select-one, select-multiple\n     *\n     * @default null\n     */\n    appendValue: string | null;\n    /**\n     * Whether selected choices should be removed from the list. By default choices are removed when they are selected in multiple select box. To always render choices pass `always`.\n     *\n     * **Input types affected:** select-one, select-multiple\n     *\n     * @default 'auto';\n     */\n    renderSelectedChoices: 'auto' | 'always' | boolean;\n    /**\n     * Whether selected choices should be removed from the list during search.\n     *\n     * **Input types affected:** select-multiple\n     *\n     * @default false;\n     */\n    searchRenderSelectedChoices: boolean;\n    /**\n     * The text that is shown whilst choices are being populated via AJAX.\n     *\n     * **Input types affected:** select-one, select-multiple\n     *\n     * @default 'Loading...'\n     */\n    loadingText: string;\n    /**\n     * The text that is shown when a user's search has returned no results. Optionally pass a function returning a string.\n     *\n     * **Input types affected:** select-one, select-multiple\n     *\n     * @default 'No results found'\n     */\n    noResultsText: string | Types.StringFunction;\n    /**\n     * The text that is shown when a user has selected all possible choices, or no choices exist. Optionally pass a function returning a string.\n     *\n     * **Input types affected:** select-multiple, select-one\n     *\n     * @default 'No choices to choose from'\n     */\n    noChoicesText: string | Types.StringFunction;\n    /**\n     * The text that is shown when a user hovers over a selectable choice. Set to empty to not reserve space for this text.\n     *\n     * **Input types affected:** select-multiple, select-one\n     *\n     * @default 'Press to select'\n     */\n    itemSelectText: string;\n    /**\n     * The text that is shown when a user has focus on the input but has already reached the **max item count** [https://github.com/jshjohnson/Choices#maxitemcount]. To access the max item count, pass a function with a `maxItemCount` argument (see the **default config** [https://github.com/jshjohnson/Choices#setup] for an example), otherwise pass a string.\n     *\n     * **Input types affected:** text\n     *\n     * @default\n     * ```\n     * (maxItemCount) => `Only ${maxItemCount} values can be added.`;\n     * ```\n     */\n    maxItemText: string | Types.NoticeLimitFunction;\n    /**\n     * If no duplicates are allowed, and the value already exists in the array.\n     *\n     * Return type must be safe to insert into HTML (ie use the 1st argument which is sanitised)\n     *\n     * @default 'Only unique values can be added'\n     */\n    uniqueItemText: string | Types.NoticeStringFunction;\n    /**\n     * The text that is shown when addItemFilter is passed and it returns false\n     *\n     * Return type must be safe to insert into HTML (ie use the 1st argument which is sanitised)\n     *\n     * **Input types affected:** text\n     *\n     * @default 'Only values matching specific conditions can be added'\n     */\n    customAddItemText: string | Types.NoticeStringFunction;\n    /**\n     * Compare choice and value in appropriate way (e.g. deep equality for objects). To compare choice and value, pass a function with a `valueComparer` argument (see the [default config](https://github.com/jshjohnson/Choices#setup) for an example).\n     *\n     * **Input types affected:** select-one, select-multiple\n     *\n     * @default\n     * ```\n     * (choice, item) => choice === item;\n     * ```\n     */\n    valueComparer: Types.ValueCompareFunction;\n    /**\n     * Classes added to HTML generated by  By default classnames follow the BEM notation.\n     *\n     * **Input types affected:** text, select-one, select-multiple\n     */\n    classNames: ClassNames;\n    /**\n     * Choices uses the great Fuse library for searching. You can find more options here: https://fusejs.io/api/options.html\n     */\n    fuseOptions: IFuseOptions<unknown>;\n    /**\n     * ID of the connected label to improve a11y. If set, aria-labelledby will be added.\n     */\n    labelId: string;\n    /**\n     * Function to run once Choices initialises.\n     *\n     * **Input types affected:** text, select-one, select-multiple\n     *\n     * @note For each callback, this refers to the current instance of  This can be useful if you need access to methods `(this.disable())` or the config object `(this.config)`.\n     *\n     * @default null\n     */\n    callbackOnInit: (() => void) | null;\n    /**\n     * Function to run on template creation. Through this callback it is possible to provide custom templates for the various components of Choices (see terminology). For Choices to work with custom templates, it is important you maintain the various data attributes defined here [https://github.com/jshjohnson/Choices/blob/67f29c286aa21d88847adfcd6304dc7d068dc01f/assets/scripts/src/choices.js#L1993-L2067].\n     *\n     * **Input types affected:** text, select-one, select-multiple\n     *\n     * @note For each callback, `this` refers to the current instance of Choices. This can be useful if you need access to methods `(this.disable())`.\n     *\n     * @example\n     * ```\n     * const example = new Choices(element, {\n     *   callbackOnCreateTemplates: function (template, originalTemplates, getClassNames) {\n     *     var classNames = this.config.classNames;\n     *     return {\n     *       item: (data) => {\n     *         return template(`\n     *           <div class=\"${getClassNames(classNames.item).join(' ')} ${data.highlighted ? classNames.highlightedState : classNames.itemSelectable}\" data-item data-id=\"${data.id}\" data-value=\"${data.value}\" ${data.active ? 'aria-selected=\"true\"' : ''} ${data.disabled ? 'aria-disabled=\"true\"' : ''}>\n     *             <span>&bigstar;</span> ${data.label}\n     *           </div>\n     *         `);\n     *       },\n     *       choice: (data) => {\n     *         return template(`\n     *           <div class=\"${getClassNames(classNames.item).join(' ')} ${classNames.itemChoice} ${data.disabled ? classNames.itemDisabled : classNames.itemSelectable}\" data-select-text=\"${this.config.itemSelectText}\" data-choice ${data.disabled ? 'data-choice-disabled aria-disabled=\"true\"' : 'data-choice-selectable'} data-id=\"${data.id}\" data-value=\"${data.value}\" ${data.groupId ? 'role=\"treeitem\"' : 'role=\"option\"'}>\n     *             <span>&bigstar;</span> ${data.label}\n     *           </div>\n     *         `);\n     *       },\n     *     };\n     *   }\n     * });\n     * ```\n     *\n     * @default null\n     */\n    callbackOnCreateTemplates: CallbackOnCreateTemplatesFn | null;\n    appendGroupInSearch: boolean;\n}\n"
  },
  {
    "path": "public/types/src/scripts/interfaces/passed-element-type.d.ts",
    "content": "import { Types } from './types';\nexport declare const PassedElementTypes: {\n    readonly Text: \"text\";\n    readonly SelectOne: \"select-one\";\n    readonly SelectMultiple: \"select-multiple\";\n};\nexport type PassedElementType = Types.ValueOf<typeof PassedElementTypes>;\n"
  },
  {
    "path": "public/types/src/scripts/interfaces/passed-element.d.ts",
    "content": "import { InputChoice } from './input-choice';\nimport { EventChoice } from './event-choice';\n/**\n * Events fired by Choices behave the same as standard events. Each event is triggered on the element passed to Choices (accessible via `this.passedElement`. Arguments are accessible within the `event.detail` object.\n */\nexport interface EventMap {\n    /**\n     * Triggered each time an item is added (programmatically or by the user).\n     *\n     * **Input types affected:** text, select-one, select-multiple\n     *\n     * Arguments: id, value, label, groupValue\n     */\n    addItem: CustomEvent<EventChoice>;\n    /**\n     * Triggered each time an item is removed (programmatically or by the user).\n     *\n     * **Input types affected:** text, select-one, select-multiple\n     *\n     * Arguments: id, value, label, groupValue\n     */\n    removeItem: CustomEvent<EventChoice | undefined>;\n    /**\n     * Triggered each time an item is highlighted.\n     *\n     * **Input types affected:** text, select-multiple\n     *\n     * Arguments: id, value, label, groupValue\n     */\n    highlightItem: CustomEvent<EventChoice | undefined>;\n    /**\n     * Triggered each time an item is unhighlighted.\n     *\n     * **Input types affected:** text, select-multiple\n     *\n     * Arguments: id, value, label, groupValue\n     */\n    unhighlightItem: CustomEvent<EventChoice | undefined>;\n    /**\n     * Triggered each time a choice is selected **by a user**, regardless if it changes the value of the input.\n     *\n     * **Input types affected:** select-one, select-multiple\n     *\n     * Arguments: choice: Choice\n     */\n    choice: CustomEvent<{\n        choice: InputChoice;\n    }>;\n    /**\n     * Triggered each time an item is added/removed **by a user**.\n     *\n     * **Input types affected:** text, select-one, select-multiple\n     *\n     * Arguments: value\n     */\n    change: CustomEvent<{\n        value: string;\n    }>;\n    /**\n     * Triggered when a user types into an input to search choices. When a search is ended, a search event with an empty value with no resultCount is triggered.\n     *\n     * **Input types affected:** select-one, select-multiple\n     *\n     * Arguments: value, resultCount\n     */\n    search: CustomEvent<{\n        value: string;\n        resultCount: number;\n    }>;\n    /**\n     * Triggered when the dropdown is shown.\n     *\n     * **Input types affected:** select-one, select-multiple\n     *\n     * Arguments: -\n     */\n    showDropdown: CustomEvent<undefined>;\n    /**\n     * Triggered when the dropdown is hidden.\n     *\n     * **Input types affected:** select-one, select-multiple\n     *\n     * Arguments: -\n     */\n    hideDropdown: CustomEvent<undefined>;\n    /**\n     * Triggered when a choice from the dropdown is highlighted.\n     *\n     * Input types affected: select-one, select-multiple\n     * Arguments: el is the choice.passedElement that was affected.\n     */\n    highlightChoice: CustomEvent<{\n        el: HTMLElement;\n    }>;\n}\n"
  },
  {
    "path": "public/types/src/scripts/interfaces/position-options-type.d.ts",
    "content": "export type PositionOptionsType = 'auto' | 'top' | 'bottom';\n"
  },
  {
    "path": "public/types/src/scripts/interfaces/search.d.ts",
    "content": "export interface SearchResult<T extends object> {\n    item: T;\n    score: number;\n    rank: number;\n}\nexport interface Searcher<T extends object> {\n    reset(): void;\n    isEmptyIndex(): boolean;\n    index(data: T[]): void;\n    search(needle: string): SearchResult<T>[];\n}\n"
  },
  {
    "path": "public/types/src/scripts/interfaces/state.d.ts",
    "content": "import { ChoiceFull } from './choice-full';\nimport { GroupFull } from './group-full';\nexport interface State {\n    choices: ChoiceFull[];\n    groups: GroupFull[];\n    items: ChoiceFull[];\n}\nexport type StateChangeSet = {\n    [K in keyof State]: boolean;\n};\n"
  },
  {
    "path": "public/types/src/scripts/interfaces/store.d.ts",
    "content": "import { StateChangeSet, State } from './state';\nimport { ChoiceFull } from './choice-full';\nimport { GroupFull } from './group-full';\nimport { ActionTypes } from './action-type';\nexport interface AnyAction<A extends ActionTypes = ActionTypes> {\n    type: A;\n}\nexport interface StateUpdate<T> {\n    update: boolean;\n    state: T;\n}\nexport type Reducer<T> = (state: T, action: AnyAction, context?: unknown) => StateUpdate<T>;\nexport type StoreListener = (changes: StateChangeSet) => void;\nexport interface Store {\n    dispatch(action: AnyAction): void;\n    subscribe(onChange: StoreListener): void;\n    withTxn(func: () => void): void;\n    reset(): void;\n    get defaultState(): State;\n    /**\n     * Get store object\n     */\n    get state(): State;\n    /**\n     * Get items from store\n     */\n    get items(): ChoiceFull[];\n    /**\n     * Get highlighted items from store\n     */\n    get highlightedActiveItems(): ChoiceFull[];\n    /**\n     * Get choices from store\n     */\n    get choices(): ChoiceFull[];\n    /**\n     * Get active choices from store\n     */\n    get activeChoices(): ChoiceFull[];\n    /**\n     * Get choices that can be searched (excluding placeholders,\n     * optionally excluding disabled based on config)\n     */\n    get searchableChoices(): ChoiceFull[];\n    /**\n     * Get groups from store\n     */\n    get groups(): GroupFull[];\n    /**\n     * Get active groups from store\n     */\n    get activeGroups(): GroupFull[];\n    /**\n     * Get loading state from store\n     */\n    inTxn(): boolean;\n    /**\n     * Get single choice by it's ID\n     */\n    getChoiceById(id: number): ChoiceFull | undefined;\n    /**\n     * Get group by group id\n     */\n    getGroupById(id: number): GroupFull | undefined;\n}\n"
  },
  {
    "path": "public/types/src/scripts/interfaces/string-pre-escaped.d.ts",
    "content": "export interface StringPreEscaped {\n    readonly trusted: string;\n}\n"
  },
  {
    "path": "public/types/src/scripts/interfaces/string-untrusted.d.ts",
    "content": "export interface StringUntrusted {\n    readonly escaped: string;\n    readonly raw: string;\n}\n"
  },
  {
    "path": "public/types/src/scripts/interfaces/templates.d.ts",
    "content": "import { PassedElementType } from './passed-element-type';\nimport { StringPreEscaped } from './string-pre-escaped';\nimport { ChoiceFull } from './choice-full';\nimport { GroupFull } from './group-full';\nimport { Options } from './options';\nimport { Types } from './types';\nexport type TemplateOptions = Pick<Options, 'classNames' | 'allowHTML' | 'removeItemButtonAlignLeft' | 'removeItemIconText' | 'removeItemLabelText' | 'searchEnabled' | 'labelId'>;\nexport declare const NoticeTypes: {\n    readonly noChoices: \"no-choices\";\n    readonly noResults: \"no-results\";\n    readonly addChoice: \"add-choice\";\n    readonly generic: \"\";\n};\nexport type NoticeType = Types.ValueOf<typeof NoticeTypes>;\nexport type CallbackOnCreateTemplatesFn = (template: Types.StrToEl, escapeForTemplate: Types.EscapeForTemplateFn, getClassNames: Types.GetClassNamesFn) => Partial<Templates>;\nexport interface Templates {\n    containerOuter(options: TemplateOptions, dir: HTMLElement['dir'], isSelectElement: boolean, isSelectOneElement: boolean, searchEnabled: boolean, passedElementType: PassedElementType, labelId: string): HTMLDivElement;\n    containerInner({ classNames: { containerInner } }: TemplateOptions): HTMLDivElement;\n    itemList(options: TemplateOptions, isSelectOneElement: boolean): HTMLDivElement;\n    placeholder(options: TemplateOptions, value: StringPreEscaped | string): HTMLDivElement;\n    item(options: TemplateOptions, choice: ChoiceFull, removeItemButton: boolean): HTMLDivElement;\n    choiceList(options: TemplateOptions, isSelectOneElement: boolean): HTMLDivElement;\n    choiceGroup(options: TemplateOptions, group: GroupFull): HTMLDivElement;\n    choice(options: TemplateOptions, choice: ChoiceFull, selectText: string, groupText?: string): HTMLDivElement;\n    input(options: TemplateOptions, placeholderValue: string | null): HTMLInputElement;\n    dropdown(options: TemplateOptions): HTMLDivElement;\n    notice(options: TemplateOptions, innerText: string, type: NoticeType): HTMLDivElement;\n    option(choice: ChoiceFull): HTMLOptionElement;\n}\n"
  },
  {
    "path": "public/types/src/scripts/interfaces/types.d.ts",
    "content": "import { StringUntrusted } from './string-untrusted';\nimport { StringPreEscaped } from './string-pre-escaped';\nimport { EventChoice } from './event-choice';\nexport declare namespace Types {\n    type StrToEl = (str: string) => HTMLElement | HTMLInputElement | HTMLOptionElement;\n    type EscapeForTemplateFn = (allowHTML: boolean, s: StringUntrusted | StringPreEscaped | string) => string;\n    type GetClassNamesFn = (s: string | Array<string>) => string;\n    type StringFunction = () => string;\n    type NoticeStringFunction = (value: string, valueRaw: string, item?: EventChoice) => string;\n    type NoticeLimitFunction = (maxItemCount: number) => string;\n    type FilterFunction = (value: string) => boolean;\n    type ValueCompareFunction = (value1: string, value2: string) => boolean;\n    interface RecordToCompare {\n        value?: StringUntrusted | string;\n        label?: StringUntrusted | string;\n    }\n    type ValueOf<T extends object> = T[keyof T];\n    type CustomProperties = Record<string, any> | string;\n}\n"
  },
  {
    "path": "public/types/src/scripts/lib/choice-input.d.ts",
    "content": "import { InputChoice } from '../interfaces/input-choice';\nimport { InputGroup } from '../interfaces/input-group';\nimport { GroupFull } from '../interfaces/group-full';\nimport { ChoiceFull } from '../interfaces/choice-full';\ntype MappedInputTypeToChoiceType<T extends string | InputChoice | InputGroup> = T extends InputGroup ? GroupFull : ChoiceFull;\nexport declare const coerceBool: (arg: unknown, defaultValue?: boolean) => boolean;\nexport declare const stringToHtmlClass: (input: string | string[] | undefined) => string[] | undefined;\nexport declare const mapInputToChoice: <T extends string | InputChoice | InputGroup>(value: T, allowGroup: boolean, allowRawString?: boolean) => MappedInputTypeToChoiceType<T>;\nexport {};\n"
  },
  {
    "path": "public/types/src/scripts/lib/html-guard-statements.d.ts",
    "content": "export declare const isHtmlInputElement: (e: Element) => e is HTMLInputElement;\nexport declare const isHtmlSelectElement: (e: Element) => e is HTMLSelectElement;\nexport declare const isHtmlOption: (e: Element) => e is HTMLOptionElement;\nexport declare const isHtmlOptgroup: (e: Element) => e is HTMLOptGroupElement;\n"
  },
  {
    "path": "public/types/src/scripts/lib/utils.d.ts",
    "content": "import { EventTypes } from '../interfaces/event-type';\nimport { StringUntrusted } from '../interfaces/string-untrusted';\nimport { StringPreEscaped } from '../interfaces/string-pre-escaped';\nimport { ChoiceFull } from '../interfaces/choice-full';\nimport { Types } from '../interfaces/types';\nimport { EventChoice } from '../interfaces';\nexport declare const generateId: (element: HTMLInputElement | HTMLSelectElement, prefix: string) => string;\nexport declare const getAdjacentEl: (startEl: HTMLElement, selector: string, direction?: number) => HTMLElement | null;\nexport declare const isScrolledIntoView: (element: HTMLElement, parent: HTMLElement, direction?: number) => boolean;\nexport declare const sanitise: <T>(value: T | StringUntrusted | StringPreEscaped | string) => T | string;\nexport declare const strToEl: (str: string) => Element;\nexport declare const resolveStringFunction: (fn: Types.StringFunction | string) => string;\nexport declare const unwrapStringForRaw: (s?: StringUntrusted | StringPreEscaped | string) => string;\nexport declare const unwrapStringForEscaped: (s?: StringUntrusted | StringPreEscaped | string) => string;\nexport declare const getChoiceForOutput: (choice: ChoiceFull, keyCode?: number) => EventChoice;\nexport declare const resolveNoticeFunction: (fn: Types.NoticeStringFunction | string, value: StringUntrusted | StringPreEscaped | string, item?: EventChoice) => string;\nexport declare const escapeForTemplate: (allowHTML: boolean, s: StringUntrusted | StringPreEscaped | string) => string;\nexport declare const setElementHtml: (el: HTMLElement, allowHtml: boolean, html: StringUntrusted | StringPreEscaped | string) => void;\nexport declare const sortByAlpha: ({ value, label }: Types.RecordToCompare, { value: value2, label: label2 }: Types.RecordToCompare) => number;\nexport declare const sortByScore: (a: Pick<ChoiceFull, \"score\">, b: Pick<ChoiceFull, \"score\">) => number;\nexport declare const sortByRank: (a: Pick<ChoiceFull, \"rank\">, b: Pick<ChoiceFull, \"rank\">) => number;\nexport declare const dispatchEvent: (element: HTMLElement, type: EventTypes, customArgs?: object | null) => boolean;\nexport declare const cloneObject: <T>(obj: T) => T;\n/**\n * Returns an array of keys present on the first but missing on the second object\n */\nexport declare const diff: (a: Record<string, any>, b: Record<string, any>) => string[];\nexport declare const getClassNames: (ClassNames: Array<string> | string) => Array<string>;\nexport declare const getClassNamesSelector: (option: string | Array<string> | null) => string;\nexport declare const addClassesToElement: (element: HTMLElement, className: Array<string> | string) => void;\nexport declare const removeClassesFromElement: (element: HTMLElement, className: Array<string> | string) => void;\nexport declare const parseCustomProperties: (customProperties?: string) => object | string;\nexport declare const updateClassList: (item: ChoiceFull, add: string | string[], remove: string | string[]) => void;\n"
  },
  {
    "path": "public/types/src/scripts/reducers/choices.d.ts",
    "content": "import { Options, State } from '../interfaces';\nimport { StateUpdate } from '../interfaces/store';\nimport { ChoiceActions } from '../actions/choices';\nimport { ItemActions } from '../actions/items';\ntype ActionTypes = ChoiceActions | ItemActions;\ntype StateType = State['choices'];\nexport default function choices(s: StateType, action: ActionTypes, context?: Options): StateUpdate<StateType>;\nexport {};\n"
  },
  {
    "path": "public/types/src/scripts/reducers/groups.d.ts",
    "content": "import { GroupActions } from '../actions/groups';\nimport { State } from '../interfaces/state';\nimport { StateUpdate } from '../interfaces/store';\nimport { ChoiceActions } from '../actions/choices';\ntype ActionTypes = ChoiceActions | GroupActions;\ntype StateType = State['groups'];\nexport default function groups(s: StateType, action: ActionTypes): StateUpdate<StateType>;\nexport {};\n"
  },
  {
    "path": "public/types/src/scripts/reducers/items.d.ts",
    "content": "import { ItemActions } from '../actions/items';\nimport { State } from '../interfaces/state';\nimport { ChoiceActions } from '../actions/choices';\nimport { Options } from '../interfaces';\nimport { StateUpdate } from '../interfaces/store';\ntype ActionTypes = ChoiceActions | ItemActions;\ntype StateType = State['items'];\nexport default function items(s: StateType, action: ActionTypes, context?: Options): StateUpdate<StateType>;\nexport {};\n"
  },
  {
    "path": "public/types/src/scripts/search/fuse.d.ts",
    "content": "import { default as FuseFull, IFuseOptions } from 'fuse.js';\nimport { default as FuseBasic } from 'fuse.js/basic';\nimport { Options } from '../interfaces/options';\nimport { Searcher, SearchResult } from '../interfaces/search';\nexport declare class SearchByFuse<T extends object> implements Searcher<T> {\n    _fuseOptions: IFuseOptions<T>;\n    _haystack: T[];\n    _fuse: FuseFull<T> | FuseBasic<T> | undefined;\n    constructor(config: Options);\n    index(data: T[]): void;\n    reset(): void;\n    isEmptyIndex(): boolean;\n    search(needle: string): SearchResult<T>[];\n}\n"
  },
  {
    "path": "public/types/src/scripts/search/index.d.ts",
    "content": "import { Options } from '../interfaces';\nimport { Searcher } from '../interfaces/search';\nexport declare function getSearcher<T extends object>(config: Options): Searcher<T>;\n"
  },
  {
    "path": "public/types/src/scripts/search/kmp.d.ts",
    "content": "import { Options } from '../interfaces';\nimport { Searcher, SearchResult } from '../interfaces/search';\nexport declare class SearchByKMP<T extends object> implements Searcher<T> {\n    _fields: string[];\n    _haystack: T[];\n    constructor(config: Options);\n    index(data: T[]): void;\n    reset(): void;\n    isEmptyIndex(): boolean;\n    search(_needle: string): SearchResult<T>[];\n}\n"
  },
  {
    "path": "public/types/src/scripts/search/prefix-filter.d.ts",
    "content": "import { Options } from '../interfaces';\nimport { Searcher, SearchResult } from '../interfaces/search';\nexport declare class SearchByPrefixFilter<T extends object> implements Searcher<T> {\n    _fields: string[];\n    _haystack: T[];\n    constructor(config: Options);\n    index(data: T[]): void;\n    reset(): void;\n    isEmptyIndex(): boolean;\n    search(_needle: string): SearchResult<T>[];\n}\n"
  },
  {
    "path": "public/types/src/scripts/store/store.d.ts",
    "content": "import { AnyAction, Store as IStore, StoreListener } from '../interfaces/store';\nimport { StateChangeSet, State } from '../interfaces/state';\nimport { ChoiceFull } from '../interfaces/choice-full';\nimport { GroupFull } from '../interfaces/group-full';\nexport default class Store<T> implements IStore {\n    _state: State;\n    _listeners: StoreListener[];\n    _txn: number;\n    _changeSet?: StateChangeSet;\n    _context: T;\n    constructor(context: T);\n    get defaultState(): State;\n    changeSet(init: boolean): StateChangeSet;\n    reset(): void;\n    subscribe(onChange: StoreListener): this;\n    dispatch(action: AnyAction): void;\n    withTxn(func: () => void): void;\n    /**\n     * Get store object\n     */\n    get state(): State;\n    /**\n     * Get items from store\n     */\n    get items(): ChoiceFull[];\n    /**\n     * Get highlighted items from store\n     */\n    get highlightedActiveItems(): ChoiceFull[];\n    /**\n     * Get choices from store\n     */\n    get choices(): ChoiceFull[];\n    /**\n     * Get active choices from store\n     */\n    get activeChoices(): ChoiceFull[];\n    /**\n     * Get choices that can be searched (excluding placeholders or disabled choices)\n     */\n    get searchableChoices(): ChoiceFull[];\n    /**\n     * Get groups from store\n     */\n    get groups(): GroupFull[];\n    /**\n     * Get active groups from store\n     */\n    get activeGroups(): GroupFull[];\n    inTxn(): boolean;\n    /**\n     * Get single choice by it's ID\n     */\n    getChoiceById(id: number): ChoiceFull | undefined;\n    /**\n     * Get group by group id\n     */\n    getGroupById(id: number): GroupFull | undefined;\n}\n"
  },
  {
    "path": "public/types/src/scripts/templates.d.ts",
    "content": "/**\n * Helpers to create HTML elements used by Choices\n * Can be overridden by providing `callbackOnCreateTemplates` option.\n * `Choices.defaults.templates` allows access to the default template methods from `callbackOnCreateTemplates`\n */\nimport { Templates as TemplatesInterface } from './interfaces/templates';\ndeclare const templates: TemplatesInterface;\nexport default templates;\n"
  },
  {
    "path": "scripts/lint-staged.config.js",
    "content": "module.exports = {\n  '*.js': ['eslint --fix --quiet -f visualstudio', 'git add'],\n  '*.{ts,scss,yaml,yml,md,html,json,babelrc,eslintrc}': [\n    'prettier --write',\n    'git add',\n  ],\n  'src/icons/*.svg': [\n    'prettier --write --parser=html --html-whitespace-sensitivity=ignore',\n    'git add',\n  ],\n  '.codecov.yml': () =>\n    'curl -f --silent --data-binary @.codecov.yml https://codecov.io/validate',\n  'src/scripts/**/*.js': () => 'npm run test:unit',\n};\n"
  },
  {
    "path": "scripts/rollup.config.mjs",
    "content": "import replace from '@rollup/plugin-replace';\nimport nodeResolve from'@rollup/plugin-node-resolve';\nimport babel from '@rollup/plugin-babel';\nimport terser from '@rollup/plugin-terser';\nimport typescript from '@rollup/plugin-typescript';\nimport * as fs from 'node:fs';\nimport server from './server.mjs';\n\n// @ts-ignore\nconst pckg = require('../package.json');\n\nconst buildFeatures = {\n  CHOICES_SEARCH_FUSE: \"full\", // \"basic\" / \"null\"\n  CHOICES_SEARCH_KMP: \"0\", // \"1\"\n  CHOICES_CAN_USE_DOM: \"1\", // \"0\"\n}\n\n// Allow the following to manual set feature flags;\n// npm run js:build-dev -- --environment SEARCH_FUSE:null\nlet defaultBuild = {};\nObject.keys(buildFeatures).forEach((k) => {\n  defaultBuild[k] = process.env[k] || buildFeatures[k];\n})\n\nconst builds = [\n  {\n    name: \".\",\n    features: defaultBuild\n  },\n  {\n    name: \"search-basic\",\n    features: {\n      ...buildFeatures,\n      CHOICES_SEARCH_FUSE: \"basic\"\n    }\n  },\n  {\n    name: \"search-prefix\",\n    features: {\n      ...buildFeatures,\n      CHOICES_SEARCH_FUSE: \"null\"\n    }\n  },\n  {\n    name: \"search-kmp\",\n    features: {\n      ...buildFeatures,\n      CHOICES_SEARCH_KMP: \"1\"\n    }\n  },\n];\n\nconst outputTypes = {\n  js : {\n    prefix: 'iife',\n    ext: 'js',\n    format: 'iife',\n    default: false,\n  },\n  umd : {\n    ext: 'js',\n    format: 'umd',\n    default: true,\n  },\n  cjs : {\n    ext: 'cjs',\n    format: 'cjs',\n    default: false,\n  },\n  mjs : {\n    ext: 'mjs',\n    format: 'es',\n    default: true,\n  },\n};\n\nconst OUTPUT_TYPES = (process.env.OUTPUT_TYPES || Object.keys(outputTypes).filter(k => outputTypes[k].default).join(',')).split(',')\n\nconst FILENAME = 'choices'\nconst VERSION = process.env.VERSION || pckg.version\nconst AUTHOR = pckg.author\nconst HOMEPAGE = pckg.homepage\nconst banner = `/*! choices.js v${VERSION} | © ${new Date().getFullYear()} ${AUTHOR} | ${HOMEPAGE} */\\n`\n\nconst withDeclarations = !!process.env.WITH_D_TS_FILES;\nif (withDeclarations) {\n  [\n    'public/types/src',\n    'public/assets/scripts',\n  ].forEach((p) => {\n    if (fs.existsSync(p)) {\n      fs.rmSync(p, { recursive: true });\n    }\n\n    fs.mkdirSync(p, { recursive: true });\n  });\n}\n\nconst candidateBuilds = process.env.TARGET\n  ? builds.filter((build) => build.name === process.env.TARGET)\n  : builds;\n\nconst suffix = (s, suffix) => {\n  return s + (suffix ? '.' + suffix : '')\n}\n\nfunction genConfig(buildConfig) {\n  // built-in vars\n  const vars = {\n    __VERSION__: VERSION,\n    preventAssignment: true,\n    'process.env.NODE_ENV': JSON.stringify('production')\n  }\n\n  if ('features' in buildConfig) {\n    Object.keys(buildConfig.features).forEach((key) => {\n      if (buildConfig.features[key] === 'undefined' || buildConfig.features[key] === 'null') {\n        vars[`process.env.${key}`] = 'false';\n      } else {\n        vars[`process.env.${key}`] = JSON.stringify(buildConfig.features[key])\n      }\n    })\n  }\n\n  const config = {\n    input: 'src/entry.js',\n    plugins: [\n      nodeResolve(),\n      typescript({\n        tsconfig: 'src/tsconfig.json',\n        // https://github.com/rollup/plugins/issues/1495\n        // @rollup/plugin-typescript just doesn't want to reliably generate .d.ts files when \"composite\" is true, so just copy the tsconfig.json definition around\n        // Additionally tsc no longer accepts relative directories which escape declarationDir\n        \"declaration\": withDeclarations,\n        // declarationDir in src/tsconfig.json with a value of \"./\" magically maps to \"./src\" here...\n        \"declarationDir\": withDeclarations ? \"./src\" : undefined,\n        \"declarationMap\": false,\n      }),\n      replace(vars)\n    ],\n    output: [],\n  }\n\n  const output = [false, true];\n  output.forEach((minify) => {\n    OUTPUT_TYPES.forEach((t) => {\n      const type = outputTypes[t];\n      if (!type) {\n        return;\n      }\n\n      if (minify && type.format === 'es') {\n        return;\n      }\n\n      let f = `public/assets/scripts/${FILENAME}`;\n\n      f = suffix(f, buildConfig.name !== '.' ? buildConfig.name : '');\n      f = suffix(f, type.prefix ? type.prefix : '');\n      f = suffix(f, minify ? 'min' : '');\n      f = suffix(f, type.ext);\n\n      const output = {\n        banner,\n        file: f,\n        format: type.format,\n        name: 'Choices',\n        exports: 'default',\n        plugins: []\n      };\n      if (type.format !== 'es') {\n        config.plugins.push(babel({ babelHelpers: 'bundled' }))\n      }\n\n      if (minify && type.format !== 'es') {\n        output.plugins.push(terser({\n          compress: {\n            passes: 2,\n            pure_getters: true,\n            pure_new: true,\n            // unsafe: true,\n          }\n        }))\n      }\n\n      config.output.push(output);\n    })\n  });\n\n  if (config.output.length === 0) {\n    return false;\n  }\n\n  return config\n}\n\nlet buildConfig = [];\ncandidateBuilds.forEach((build) => {\n  buildConfig.push(genConfig(build));\n});\n\nbuildConfig = buildConfig.filter((b) => !!b);\nif (buildConfig.length === 0) {\n  console.log('No valid build targets or feature combinations.');\n} else {\n  const localServer = server();\n  if (localServer) {\n    buildConfig[0].plugins.push(localServer)\n  }\n}\n\n// noinspection JSUnusedGlobalSymbols\nexport default buildConfig;"
  },
  {
    "path": "scripts/server.mjs",
    "content": "import dev from 'rollup-plugin-dev';\n\nexport default function server() {\n  const WATCH_HOST = process.env.WATCH_HOST;\n\n  if (!WATCH_HOST) {\n    return void 0;\n  }\n  const WATCH_PORT = process.env.WATCH_PORT || 3001;\n\n  return dev({\n    dirs: ['public'],\n    host: WATCH_HOST,\n    port: WATCH_PORT,\n    force: !!process.env.CI,\n    // silent: !!process.env.CI\n  });\n};"
  },
  {
    "path": "src/entry.js",
    "content": "import Choices from './scripts/choices';\n\nexport default Choices;\n"
  },
  {
    "path": "src/index.ts",
    "content": "import Choices from './scripts/choices';\n\nexport * from './scripts/interfaces';\nexport * from './scripts/constants';\nexport * from './scripts/defaults';\nexport { default as templates } from './scripts/templates';\n\nexport default Choices;\n"
  },
  {
    "path": "src/scripts/actions/choices.ts",
    "content": "import { ChoiceFull } from '../interfaces/choice-full';\nimport { ActionType } from '../interfaces';\nimport { SearchResult } from '../interfaces/search';\nimport { AnyAction } from '../interfaces/store';\n\nexport type ChoiceActions =\n  | AddChoiceAction\n  | RemoveChoiceAction\n  | FilterChoicesAction\n  | ActivateChoicesAction\n  | ClearChoicesAction;\n\nexport interface AddChoiceAction extends AnyAction<typeof ActionType.ADD_CHOICE> {\n  choice: ChoiceFull;\n}\n\nexport interface RemoveChoiceAction extends AnyAction<typeof ActionType.REMOVE_CHOICE> {\n  choice: ChoiceFull;\n}\n\nexport interface FilterChoicesAction extends AnyAction<typeof ActionType.FILTER_CHOICES> {\n  results: SearchResult<ChoiceFull>[];\n}\n\nexport interface ActivateChoicesAction extends AnyAction<typeof ActionType.ACTIVATE_CHOICES> {\n  active: boolean;\n}\n\n/**\n * @deprecated use clearStore() or clearChoices() instead.\n */\nexport interface ClearChoicesAction extends AnyAction<typeof ActionType.CLEAR_CHOICES> {}\n\nexport const addChoice = (choice: ChoiceFull): AddChoiceAction => ({\n  type: ActionType.ADD_CHOICE,\n  choice,\n});\n\nexport const removeChoice = (choice: ChoiceFull): RemoveChoiceAction => ({\n  type: ActionType.REMOVE_CHOICE,\n  choice,\n});\n\nexport const filterChoices = (results: SearchResult<ChoiceFull>[]): FilterChoicesAction => ({\n  type: ActionType.FILTER_CHOICES,\n  results,\n});\n\nexport const activateChoices = (active = true): ActivateChoicesAction => ({\n  type: ActionType.ACTIVATE_CHOICES,\n  active,\n});\n\n/**\n * @deprecated use clearStore() or clearChoices() instead.\n */\nexport const clearChoices = (): ClearChoicesAction => ({\n  type: ActionType.CLEAR_CHOICES,\n});\n"
  },
  {
    "path": "src/scripts/actions/groups.ts",
    "content": "import { GroupFull } from '../interfaces/group-full';\nimport { ActionType } from '../interfaces';\nimport { AnyAction } from '../interfaces/store';\n\nexport type GroupActions = AddGroupAction;\n\nexport interface AddGroupAction extends AnyAction<typeof ActionType.ADD_GROUP> {\n  group: GroupFull;\n}\n\nexport const addGroup = (group: GroupFull): AddGroupAction => ({\n  type: ActionType.ADD_GROUP,\n  group,\n});\n"
  },
  {
    "path": "src/scripts/actions/items.ts",
    "content": "import { ChoiceFull } from '../interfaces/choice-full';\nimport { ActionType } from '../interfaces';\nimport { AnyAction } from '../interfaces/store';\n\nexport type ItemActions = AddItemAction | RemoveItemAction | HighlightItemAction;\n\nexport interface AddItemAction extends AnyAction<typeof ActionType.ADD_ITEM> {\n  item: ChoiceFull;\n}\n\nexport interface RemoveItemAction extends AnyAction<typeof ActionType.REMOVE_ITEM> {\n  item: ChoiceFull;\n}\n\nexport interface HighlightItemAction extends AnyAction<typeof ActionType.HIGHLIGHT_ITEM> {\n  item: ChoiceFull;\n  highlighted: boolean;\n}\n\nexport const addItem = (item: ChoiceFull): AddItemAction => ({\n  type: ActionType.ADD_ITEM,\n  item,\n});\n\nexport const removeItem = (item: ChoiceFull): RemoveItemAction => ({\n  type: ActionType.REMOVE_ITEM,\n  item,\n});\n\nexport const highlightItem = (item: ChoiceFull, highlighted: boolean): HighlightItemAction => ({\n  type: ActionType.HIGHLIGHT_ITEM,\n  item,\n  highlighted,\n});\n"
  },
  {
    "path": "src/scripts/choices.ts",
    "content": "import { activateChoices, addChoice, removeChoice, filterChoices } from './actions/choices';\nimport { addGroup } from './actions/groups';\nimport { addItem, highlightItem, removeItem } from './actions/items';\nimport { Container, Dropdown, Input, List, WrappedInput, WrappedSelect } from './components';\nimport { DEFAULT_CONFIG } from './defaults';\nimport { InputChoice } from './interfaces/input-choice';\nimport { InputGroup } from './interfaces/input-group';\nimport { Options, ObjectsInConfig } from './interfaces/options';\nimport { StateChangeSet } from './interfaces/state';\nimport {\n  addClassesToElement,\n  diff,\n  escapeForTemplate,\n  generateId,\n  getAdjacentEl,\n  getChoiceForOutput,\n  getClassNames,\n  getClassNamesSelector,\n  isScrolledIntoView,\n  removeClassesFromElement,\n  resolveNoticeFunction,\n  resolveStringFunction,\n  sortByRank,\n  strToEl,\n  unwrapStringForEscaped,\n} from './lib/utils';\nimport Store from './store/store';\nimport { coerceBool, mapInputToChoice } from './lib/choice-input';\nimport { ChoiceFull } from './interfaces/choice-full';\nimport { GroupFull } from './interfaces/group-full';\nimport { EventChoiceValueType, EventType, KeyCodeMap, PassedElementType, PassedElementTypes } from './interfaces';\nimport { EventChoice } from './interfaces/event-choice';\nimport { NoticeType, NoticeTypes, Templates } from './interfaces/templates';\nimport { isHtmlInputElement, isHtmlSelectElement } from './lib/html-guard-statements';\nimport { Searcher } from './interfaces/search';\nimport { getSearcher } from './search';\n// eslint-disable-next-line import/no-named-default\nimport { default as defaultTemplates } from './templates';\nimport { canUseDom } from './interfaces/build-flags';\n\n/** @see {@link http://browserhacks.com/#hack-acea075d0ac6954f275a70023906050c} */\nconst IS_IE11 =\n  canUseDom &&\n  '-ms-scroll-limit' in document.documentElement.style &&\n  '-ms-ime-align' in document.documentElement.style;\n\nconst USER_DEFAULTS: Partial<Options> = {};\n\nconst parseDataSetId = (element: HTMLElement | null): number | undefined => {\n  if (!element) {\n    return undefined;\n  }\n\n  return element.dataset.id ? parseInt(element.dataset.id, 10) : undefined;\n};\n\nconst selectableChoiceIdentifier = '[data-choice-selectable]';\n\n/**\n * Choices\n * @author Josh Johnson<josh@joshuajohnson.co.uk>\n */\nclass Choices {\n  static version: string = '__VERSION__';\n\n  static get defaults(): {\n    options: Partial<Options>;\n    allOptions: Options;\n    templates: Templates;\n  } {\n    return Object.preventExtensions({\n      get options(): Partial<Options> {\n        return USER_DEFAULTS;\n      },\n      get allOptions(): Options {\n        return DEFAULT_CONFIG;\n      },\n      get templates(): Templates {\n        return defaultTemplates;\n      },\n    });\n  }\n\n  initialised: boolean;\n\n  initialisedOK?: boolean = undefined;\n\n  config: Options;\n\n  passedElement: WrappedInput | WrappedSelect;\n\n  containerOuter: Container;\n\n  containerInner: Container;\n\n  choiceList: List;\n\n  itemList: List;\n\n  input: Input;\n\n  dropdown: Dropdown;\n\n  _elementType: PassedElementType;\n\n  _isTextElement: boolean;\n\n  _isSelectOneElement: boolean;\n\n  _isSelectMultipleElement: boolean;\n\n  _isSelectElement: boolean;\n\n  _hasNonChoicePlaceholder: boolean = false;\n\n  _canAddUserChoices: boolean;\n\n  _store: Store<Options>;\n\n  _templates: Templates;\n\n  _lastAddedChoiceId: number = 0;\n\n  _lastAddedGroupId: number = 0;\n\n  _currentValue: string;\n\n  _canSearch: boolean;\n\n  _isScrollingOnIe: boolean;\n\n  _highlightPosition: number;\n\n  _wasTap: boolean;\n\n  _isSearching: boolean;\n\n  _placeholderValue: string | null;\n\n  _baseId: string;\n\n  _direction: HTMLElement['dir'];\n\n  _idNames: {\n    itemChoice: string;\n  };\n\n  _presetChoices: (ChoiceFull | GroupFull)[];\n\n  _initialItems: string[];\n\n  _searcher: Searcher<ChoiceFull>;\n\n  _notice?: {\n    type: NoticeType;\n    text: string;\n  };\n\n  _docRoot: ShadowRoot | HTMLElement;\n\n  constructor(\n    element: string | Element | HTMLInputElement | HTMLSelectElement = '[data-choice]',\n    userConfig: Partial<Options> = {},\n  ) {\n    const { defaults } = Choices;\n    this.config = {\n      ...defaults.allOptions,\n      ...defaults.options,\n      ...userConfig,\n    } as Options;\n    ObjectsInConfig.forEach((key) => {\n      this.config[key] = {\n        ...defaults.allOptions[key],\n        ...defaults.options[key],\n        ...userConfig[key],\n      };\n    });\n\n    const { config } = this;\n    if (!config.silent) {\n      this._validateConfig();\n    }\n\n    const docRoot = config.shadowRoot || document.documentElement;\n    this._docRoot = docRoot;\n    const passedElement = typeof element === 'string' ? docRoot.querySelector<HTMLElement>(element) : element;\n\n    if (\n      !passedElement ||\n      typeof passedElement !== 'object' ||\n      !(isHtmlInputElement(passedElement) || isHtmlSelectElement(passedElement))\n    ) {\n      if (!passedElement && typeof element === 'string') {\n        throw TypeError(`Selector ${element} failed to find an element`);\n      }\n      throw TypeError(`Expected one of the following types text|select-one|select-multiple`);\n    }\n\n    let elementType = passedElement.type as PassedElementType;\n    const isText = elementType === PassedElementTypes.Text;\n    if (isText || config.maxItemCount !== 1) {\n      config.singleModeForMultiSelect = false;\n    }\n    if (config.singleModeForMultiSelect) {\n      elementType = PassedElementTypes.SelectMultiple;\n    }\n    const isSelectOne = elementType === PassedElementTypes.SelectOne;\n    const isSelectMultiple = elementType === PassedElementTypes.SelectMultiple;\n    const isSelect = isSelectOne || isSelectMultiple;\n\n    this._elementType = elementType;\n    this._isTextElement = isText;\n    this._isSelectOneElement = isSelectOne;\n    this._isSelectMultipleElement = isSelectMultiple;\n    this._isSelectElement = isSelectOne || isSelectMultiple;\n    this._canAddUserChoices = (isText && config.addItems) || (isSelect && config.addChoices);\n\n    if (typeof config.renderSelectedChoices !== 'boolean') {\n      config.renderSelectedChoices = config.renderSelectedChoices === 'always' || isSelectOne;\n    }\n\n    if (config.closeDropdownOnSelect === 'auto') {\n      config.closeDropdownOnSelect = isText || isSelectOne || config.singleModeForMultiSelect;\n    } else {\n      config.closeDropdownOnSelect = coerceBool(config.closeDropdownOnSelect);\n    }\n\n    if (config.placeholder) {\n      if (config.placeholderValue) {\n        this._hasNonChoicePlaceholder = true;\n      } else if (passedElement.dataset.placeholder) {\n        this._hasNonChoicePlaceholder = true;\n        config.placeholderValue = passedElement.dataset.placeholder;\n      }\n    }\n\n    if (userConfig.addItemFilter && typeof userConfig.addItemFilter !== 'function') {\n      const re =\n        userConfig.addItemFilter instanceof RegExp ? userConfig.addItemFilter : new RegExp(userConfig.addItemFilter);\n\n      config.addItemFilter = re.test.bind(re);\n    }\n\n    if (this._isTextElement) {\n      this.passedElement = new WrappedInput({\n        element: passedElement as HTMLInputElement,\n        classNames: config.classNames,\n      });\n    } else {\n      const selectEl = passedElement as HTMLSelectElement;\n      this.passedElement = new WrappedSelect({\n        element: selectEl,\n        classNames: config.classNames,\n        template: (data: ChoiceFull): HTMLOptionElement => this._templates.option(data),\n        extractPlaceholder: config.placeholder && !this._hasNonChoicePlaceholder,\n      });\n    }\n\n    this.initialised = false;\n\n    this._store = new Store(config);\n    this._currentValue = '';\n    config.searchEnabled = !isText && config.searchEnabled;\n    this._canSearch = config.searchEnabled;\n    this._isScrollingOnIe = false;\n    this._highlightPosition = 0;\n    this._wasTap = true;\n    this._placeholderValue = this._generatePlaceholderValue();\n    this._baseId = generateId(passedElement, 'choices-');\n\n    /**\n     * setting direction in cases where it's explicitly set on passedElement\n     * or when calculated direction is different from the document\n     */\n    this._direction = passedElement.dir;\n\n    if (canUseDom && !this._direction) {\n      const { direction: elementDirection } = window.getComputedStyle(passedElement);\n      const { direction: documentDirection } = window.getComputedStyle(document.documentElement);\n      if (elementDirection !== documentDirection) {\n        this._direction = elementDirection;\n      }\n    }\n\n    this._idNames = {\n      itemChoice: 'item-choice',\n    };\n\n    this._templates = defaults.templates;\n    this._render = this._render.bind(this);\n    this._onFocus = this._onFocus.bind(this);\n    this._onBlur = this._onBlur.bind(this);\n    this._onKeyUp = this._onKeyUp.bind(this);\n    this._onKeyDown = this._onKeyDown.bind(this);\n    this._onInput = this._onInput.bind(this);\n    this._onClick = this._onClick.bind(this);\n    this._onTouchMove = this._onTouchMove.bind(this);\n    this._onTouchEnd = this._onTouchEnd.bind(this);\n    this._onMouseDown = this._onMouseDown.bind(this);\n    this._onMouseOver = this._onMouseOver.bind(this);\n    this._onFormReset = this._onFormReset.bind(this);\n    this._onSelectKey = this._onSelectKey.bind(this);\n    this._onEnterKey = this._onEnterKey.bind(this);\n    this._onEscapeKey = this._onEscapeKey.bind(this);\n    this._onDirectionKey = this._onDirectionKey.bind(this);\n    this._onDeleteKey = this._onDeleteKey.bind(this);\n    this._onChange = this._onChange.bind(this);\n    this._onInvalid = this._onInvalid.bind(this);\n\n    // If element has already been initialised with Choices, fail silently\n    if (this.passedElement.isActive) {\n      if (!config.silent) {\n        console.warn('Trying to initialise Choices on element already initialised', { element });\n      }\n\n      this.initialised = true;\n      this.initialisedOK = false;\n\n      return;\n    }\n\n    // Let's go\n    this.init();\n    // preserve the selected item list after setup for form reset\n    this._initialItems = this._store.items.map((choice) => choice.value);\n  }\n\n  init(): void {\n    if (this.initialised || this.initialisedOK !== undefined) {\n      return;\n    }\n\n    this._searcher = getSearcher<ChoiceFull>(this.config);\n    this._loadChoices();\n    this._createTemplates();\n    this._createElements();\n    this._createStructure();\n\n    if (\n      (this._isTextElement && !this.config.addItems) ||\n      this.passedElement.element.hasAttribute('disabled') ||\n      !!this.passedElement.element.closest('fieldset:disabled')\n    ) {\n      this.disable();\n    } else {\n      this.enable();\n      this._addEventListeners();\n    }\n\n    // should be triggered **after** disabled state to avoid additional re-draws\n    this._initStore();\n\n    this.initialised = true;\n    this.initialisedOK = true;\n\n    const { callbackOnInit } = this.config;\n    // Run callback if it is a function\n    if (typeof callbackOnInit === 'function') {\n      callbackOnInit.call(this);\n    }\n  }\n\n  destroy(): void {\n    if (!this.initialised) {\n      return;\n    }\n\n    this._removeEventListeners();\n    this.passedElement.reveal();\n    this.containerOuter.unwrap(this.passedElement.element);\n\n    this._store._listeners = []; // prevents select/input value being wiped\n    this.clearStore(false);\n    this._stopSearch();\n\n    this._templates = Choices.defaults.templates;\n    this.initialised = false;\n    this.initialisedOK = undefined;\n  }\n\n  enable(): this {\n    if (this.passedElement.isDisabled) {\n      this.passedElement.enable();\n    }\n\n    if (this.containerOuter.isDisabled) {\n      this._addEventListeners();\n      this.input.enable();\n      this.containerOuter.enable();\n    }\n\n    return this;\n  }\n\n  disable(): this {\n    if (!this.passedElement.isDisabled) {\n      this.passedElement.disable();\n    }\n\n    if (!this.containerOuter.isDisabled) {\n      this._removeEventListeners();\n      this.input.disable();\n      this.containerOuter.disable();\n    }\n\n    return this;\n  }\n\n  highlightItem(item: InputChoice, runEvent = true): this {\n    if (!item || !item.id) {\n      return this;\n    }\n    const choice = this._store.items.find((c) => c.id === item.id);\n    if (!choice || choice.highlighted) {\n      return this;\n    }\n\n    this._store.dispatch(highlightItem(choice, true));\n\n    if (runEvent) {\n      this.passedElement.triggerEvent(EventType.highlightItem, getChoiceForOutput(choice));\n    }\n\n    return this;\n  }\n\n  unhighlightItem(item: InputChoice, runEvent = true): this {\n    if (!item || !item.id) {\n      return this;\n    }\n    const choice = this._store.items.find((c) => c.id === item.id);\n    if (!choice || !choice.highlighted) {\n      return this;\n    }\n\n    this._store.dispatch(highlightItem(choice, false));\n\n    if (runEvent) {\n      this.passedElement.triggerEvent(EventType.unhighlightItem, getChoiceForOutput(choice));\n    }\n\n    return this;\n  }\n\n  highlightAll(): this {\n    this._store.withTxn(() => {\n      this._store.items.forEach((item) => {\n        if (!item.highlighted) {\n          this._store.dispatch(highlightItem(item, true));\n\n          this.passedElement.triggerEvent(EventType.highlightItem, getChoiceForOutput(item));\n        }\n      });\n    });\n\n    return this;\n  }\n\n  unhighlightAll(): this {\n    this._store.withTxn(() => {\n      this._store.items.forEach((item) => {\n        if (item.highlighted) {\n          this._store.dispatch(highlightItem(item, false));\n\n          this.passedElement.triggerEvent(EventType.highlightItem, getChoiceForOutput(item));\n        }\n      });\n    });\n\n    return this;\n  }\n\n  removeActiveItemsByValue(value: string): this {\n    this._store.withTxn(() => {\n      this._store.items.filter((item) => item.value === value).forEach((item) => this._removeItem(item));\n    });\n\n    return this;\n  }\n\n  removeActiveItems(excludedId?: number): this {\n    this._store.withTxn(() => {\n      this._store.items.filter(({ id }) => id !== excludedId).forEach((item) => this._removeItem(item));\n    });\n\n    return this;\n  }\n\n  removeHighlightedItems(runEvent = false): this {\n    this._store.withTxn(() => {\n      this._store.highlightedActiveItems.forEach((item) => {\n        this._removeItem(item);\n        // If this action was performed by the user\n        // trigger the event\n        if (runEvent) {\n          this._triggerChange(item.value);\n        }\n      });\n    });\n\n    return this;\n  }\n\n  showDropdown(preventInputFocus?: boolean): this {\n    if (this.dropdown.isActive) {\n      return this;\n    }\n\n    if (preventInputFocus === undefined) {\n      // eslint-disable-next-line no-param-reassign\n      preventInputFocus = !this._canSearch;\n    }\n\n    requestAnimationFrame(() => {\n      this.dropdown.show();\n      const rect = this.dropdown.element.getBoundingClientRect();\n      this.containerOuter.open(rect.bottom, rect.height);\n\n      if (!preventInputFocus) {\n        this.input.focus();\n      }\n\n      this.passedElement.triggerEvent(EventType.showDropdown);\n\n      const activeElement = this.choiceList.element.querySelector<HTMLElement>(\n        getClassNamesSelector(this.config.classNames.selectedState),\n      );\n\n      if (activeElement !== null && !isScrolledIntoView(activeElement, this.choiceList.element)) {\n        // scrollIntoView can cause entire page scrolling, scrollToChildElement causes undesired animation\n        this.choiceList.element.scrollTop = activeElement.offsetTop;\n      }\n    });\n\n    return this;\n  }\n\n  hideDropdown(preventInputBlur?: boolean): this {\n    if (!this.dropdown.isActive) {\n      return this;\n    }\n\n    this._removeHighlightedChoices();\n\n    requestAnimationFrame(() => {\n      this.dropdown.hide();\n      this.containerOuter.close();\n\n      if (!preventInputBlur && this._canSearch) {\n        this.input.removeActiveDescendant();\n        this.input.blur();\n      }\n\n      this.passedElement.triggerEvent(EventType.hideDropdown);\n    });\n\n    return this;\n  }\n\n  getValue<B extends boolean = false>(valueOnly?: B): EventChoiceValueType<B> | EventChoiceValueType<B>[] {\n    const values = this._store.items.map((item) => {\n      return (valueOnly ? item.value : getChoiceForOutput(item)) as EventChoiceValueType<B>;\n    });\n\n    return this._isSelectOneElement || this.config.singleModeForMultiSelect ? values[0] : values;\n  }\n\n  setValue(items: string[] | InputChoice[]): this {\n    if (!this.initialisedOK) {\n      this._warnChoicesInitFailed('setValue');\n\n      return this;\n    }\n\n    this._store.withTxn(() => {\n      items.forEach((value: string | InputChoice) => {\n        if (value) {\n          this._addChoice(mapInputToChoice(value, false));\n        }\n      });\n    });\n\n    // @todo integrate with Store\n    this._searcher.reset();\n\n    return this;\n  }\n\n  setChoiceByValue(value: string | string[]): this {\n    if (!this.initialisedOK) {\n      this._warnChoicesInitFailed('setChoiceByValue');\n\n      return this;\n    }\n    if (this._isTextElement) {\n      return this;\n    }\n    this._store.withTxn(() => {\n      // If only one value has been passed, convert to array\n      const choiceValue = Array.isArray(value) ? value : [value];\n\n      // Loop through each value and\n      choiceValue.forEach((val) => this._findAndSelectChoiceByValue(val));\n      this.unhighlightAll();\n    });\n\n    // @todo integrate with Store\n    this._searcher.reset();\n\n    return this;\n  }\n\n  /**\n   * Set choices of select input via an array of objects (or function that returns array of object or promise of it),\n   * a value field name and a label field name.\n   * This behaves the same as passing items via the choices option but can be called after initialising Choices.\n   * This can also be used to add groups of choices (see example 2); Optionally pass a true `replaceChoices` value to remove any existing choices.\n   * Optionally pass a `customProperties` object to add additional data to your choices (useful when searching/filtering etc).\n   *\n   * **Input types affected:** select-one, select-multiple\n   *\n   * @example\n   * ```js\n   * const example = new Choices(element);\n   *\n   * example.setChoices([\n   *   {value: 'One', label: 'Label One', disabled: true},\n   *   {value: 'Two', label: 'Label Two', selected: true},\n   *   {value: 'Three', label: 'Label Three'},\n   * ], 'value', 'label', false);\n   * ```\n   *\n   * @example\n   * ```js\n   * const example = new Choices(element);\n   *\n   * example.setChoices(async () => {\n   *   try {\n   *      const items = await fetch('/items');\n   *      return items.json()\n   *   } catch(err) {\n   *      console.error(err)\n   *   }\n   * });\n   * ```\n   *\n   * @example\n   * ```js\n   * const example = new Choices(element);\n   *\n   * example.setChoices([{\n   *   label: 'Group one',\n   *   id: 1,\n   *   disabled: false,\n   *   choices: [\n   *     {value: 'Child One', label: 'Child One', selected: true},\n   *     {value: 'Child Two', label: 'Child Two',  disabled: true},\n   *     {value: 'Child Three', label: 'Child Three'},\n   *   ]\n   * },\n   * {\n   *   label: 'Group two',\n   *   id: 2,\n   *   disabled: false,\n   *   choices: [\n   *     {value: 'Child Four', label: 'Child Four', disabled: true},\n   *     {value: 'Child Five', label: 'Child Five'},\n   *     {value: 'Child Six', label: 'Child Six', customProperties: {\n   *       description: 'Custom description about child six',\n   *       random: 'Another random custom property'\n   *     }},\n   *   ]\n   * }], 'value', 'label', false);\n   * ```\n   */\n  setChoices(\n    choicesArrayOrFetcher:\n      | (InputChoice | InputGroup)[]\n      | ((instance: Choices) => (InputChoice | InputGroup)[] | Promise<(InputChoice | InputGroup)[]>) = [],\n    value: string | null = 'value',\n    label: string = 'label',\n    replaceChoices: boolean = false,\n    clearSearchFlag: boolean = true,\n    replaceItems: boolean = false,\n  ): this | Promise<this> {\n    if (!this.initialisedOK) {\n      this._warnChoicesInitFailed('setChoices');\n\n      return this;\n    }\n    if (!this._isSelectElement) {\n      throw new TypeError(`setChoices can't be used with INPUT based Choices`);\n    }\n\n    if (typeof value !== 'string' || !value) {\n      throw new TypeError(`value parameter must be a name of 'value' field in passed objects`);\n    }\n\n    if (typeof choicesArrayOrFetcher === 'function') {\n      // it's a choices fetcher function\n      const fetcher = choicesArrayOrFetcher(this);\n\n      if (typeof Promise === 'function' && fetcher instanceof Promise) {\n        // that's a promise\n        // eslint-disable-next-line no-promise-executor-return\n        return new Promise((resolve) => requestAnimationFrame(resolve))\n          .then(() => this._handleLoadingState(true))\n          .then(() => fetcher)\n          .then((data: InputChoice[]) =>\n            this.setChoices(data, value, label, replaceChoices, clearSearchFlag, replaceItems),\n          )\n          .catch((err) => {\n            if (!this.config.silent) {\n              console.error(err);\n            }\n          })\n          .then(() => this._handleLoadingState(false))\n          .then(() => this);\n      }\n\n      // function returned something else than promise, let's check if it's an array of choices\n      if (!Array.isArray(fetcher)) {\n        throw new TypeError(\n          `.setChoices first argument function must return either array of choices or Promise, got: ${typeof fetcher}`,\n        );\n      }\n\n      // recursion with results, it's sync and choices were cleared already\n      return this.setChoices(fetcher, value, label, false);\n    }\n\n    if (!Array.isArray(choicesArrayOrFetcher)) {\n      throw new TypeError(\n        `.setChoices must be called either with array of choices with a function resulting into Promise of array of choices`,\n      );\n    }\n\n    this.containerOuter.removeLoadingState();\n\n    this._store.withTxn(() => {\n      if (clearSearchFlag) {\n        this._isSearching = false;\n      }\n      // Clear choices if needed\n      if (replaceChoices) {\n        this.clearChoices(true, replaceItems);\n      }\n      const isDefaultValue = value === 'value';\n      const isDefaultLabel = label === 'label';\n\n      choicesArrayOrFetcher.forEach((groupOrChoice: InputGroup | InputChoice) => {\n        if ('choices' in groupOrChoice) {\n          let group = groupOrChoice;\n          if (!isDefaultLabel) {\n            group = {\n              ...group,\n              label: group[label],\n            } as InputGroup;\n          }\n\n          this._addGroup(mapInputToChoice<InputGroup>(group, true));\n        } else {\n          let choice = groupOrChoice;\n          if (!isDefaultLabel || !isDefaultValue) {\n            choice = {\n              ...choice,\n              value: choice[value],\n              label: choice[label],\n            } as InputChoice;\n          }\n          const choiceFull = mapInputToChoice<InputChoice>(choice, false);\n          this._addChoice(choiceFull);\n          if (choiceFull.placeholder && !this._hasNonChoicePlaceholder) {\n            this._placeholderValue = unwrapStringForEscaped(choiceFull.label);\n          }\n        }\n      });\n\n      this.unhighlightAll();\n    });\n\n    // @todo integrate with Store\n    this._searcher.reset();\n\n    return this;\n  }\n\n  refresh(withEvents: boolean = false, selectFirstOption: boolean = false, deselectAll: boolean = false): this {\n    if (!this._isSelectElement) {\n      if (!this.config.silent) {\n        console.warn('refresh method can only be used on choices backed by a <select> element');\n      }\n\n      return this;\n    }\n\n    this._store.withTxn(() => {\n      const choicesFromOptions = (this.passedElement as WrappedSelect).optionsAsChoices();\n\n      // Build the list of items which require preserving\n      const existingItems = {};\n      if (!deselectAll) {\n        this._store.items.forEach((choice) => {\n          if (choice.id && choice.active && choice.selected) {\n            existingItems[choice.value] = true;\n          }\n        });\n      }\n\n      this.clearStore(false);\n\n      const updateChoice = (choice: ChoiceFull): void => {\n        if (deselectAll) {\n          this._store.dispatch(removeItem(choice));\n        } else if (existingItems[choice.value]) {\n          choice.selected = true;\n        }\n      };\n\n      choicesFromOptions.forEach((groupOrChoice) => {\n        if ('choices' in groupOrChoice) {\n          groupOrChoice.choices.forEach(updateChoice);\n\n          return;\n        }\n        updateChoice(groupOrChoice);\n      });\n\n      /* @todo only generate add events for the added options instead of all\n      if (withEvents) {\n        items.forEach((choice) => {\n          if (existingItems[choice.value]) {\n            this.passedElement.triggerEvent(\n              EventType.removeItem,\n              this._getChoiceForEvent(choice),\n            );\n          }\n        });\n      }\n      */\n\n      // load new choices & items\n      this._addPredefinedChoices(choicesFromOptions, selectFirstOption, withEvents);\n\n      // re-do search if required\n      if (this._isSearching) {\n        this._searchChoices(this.input.value);\n      }\n    });\n\n    return this;\n  }\n\n  removeChoice(value: string): this {\n    const choice = this._store.choices.find((c) => c.value === value);\n    if (!choice) {\n      return this;\n    }\n    this._clearNotice();\n    this._store.dispatch(removeChoice(choice));\n    // @todo integrate with Store\n    this._searcher.reset();\n\n    if (choice.selected) {\n      this.passedElement.triggerEvent(EventType.removeItem, getChoiceForOutput(choice));\n    }\n\n    return this;\n  }\n\n  clearChoices(clearOptions: boolean = true, clearItems: boolean = false): this {\n    if (clearOptions) {\n      if (clearItems) {\n        this.passedElement.element.replaceChildren('');\n      } else {\n        this.passedElement.element.querySelectorAll(':not([selected])').forEach((el): void => {\n          el.remove();\n        });\n      }\n    }\n    this.itemList.element.replaceChildren('');\n    this.choiceList.element.replaceChildren('');\n    this._clearNotice();\n    this._store.withTxn(() => {\n      const items = clearItems ? [] : this._store.items;\n      this._store.reset();\n      items.forEach((item: ChoiceFull): void => {\n        this._store.dispatch(addChoice(item));\n        this._store.dispatch(addItem(item));\n      });\n    });\n    // @todo integrate with Store\n    this._searcher.reset();\n\n    return this;\n  }\n\n  clearStore(clearOptions: boolean = true): this {\n    this.clearChoices(clearOptions, true);\n    this._stopSearch();\n    this._lastAddedChoiceId = 0;\n    this._lastAddedGroupId = 0;\n\n    return this;\n  }\n\n  clearInput(): this {\n    const shouldSetInputWidth = !this._isSelectOneElement;\n    this.input.clear(shouldSetInputWidth);\n    this._stopSearch();\n\n    return this;\n  }\n\n  _validateConfig(): void {\n    const { config } = this;\n    const invalidConfigOptions = diff(config, DEFAULT_CONFIG);\n    if (invalidConfigOptions.length) {\n      console.warn('Unknown config option(s) passed', invalidConfigOptions.join(', '));\n    }\n\n    if (config.allowHTML && config.allowHtmlUserInput) {\n      if (config.addItems) {\n        console.warn(\n          'Warning: allowHTML/allowHtmlUserInput/addItems all being true is strongly not recommended and may lead to XSS attacks',\n        );\n      }\n      if (config.addChoices) {\n        console.warn(\n          'Warning: allowHTML/allowHtmlUserInput/addChoices all being true is strongly not recommended and may lead to XSS attacks',\n        );\n      }\n    }\n  }\n\n  _render(changes: StateChangeSet = { choices: true, groups: true, items: true }): void {\n    if (this._store.inTxn()) {\n      return;\n    }\n\n    if (this._isSelectElement) {\n      if (changes.choices || changes.groups) {\n        this._renderChoices();\n      }\n    }\n\n    if (changes.items) {\n      this._renderItems();\n    }\n  }\n\n  _renderChoices(): void {\n    if (!this._canAddItems()) {\n      return; // block rendering choices if the input limit is reached.\n    }\n\n    const { config, _isSearching: isSearching } = this;\n    const { activeGroups, activeChoices } = this._store;\n\n    const renderLimit = isSearching ? config.searchResultLimit : config.renderChoiceLimit;\n\n    if (this._isSelectElement) {\n      const backingOptions = activeChoices.filter((choice) => !choice.element);\n      if (backingOptions.length) {\n        (this.passedElement as WrappedSelect).addOptions(backingOptions);\n      }\n    }\n\n    const fragment = document.createDocumentFragment();\n    const renderableChoices = (choices: ChoiceFull[]): ChoiceFull[] =>\n      choices.filter(\n        (choice) =>\n          !choice.placeholder &&\n          (isSearching\n            ? (config.searchRenderSelectedChoices || !choice.selected) && !!choice.rank\n            : config.renderSelectedChoices || !choice.selected),\n      );\n\n    const showLabel = config.appendGroupInSearch && isSearching;\n    let selectableChoices = false;\n    let highlightedEl: HTMLElement | null = null;\n    const renderChoices = (choices: ChoiceFull[], withinGroup: boolean): void => {\n      if (isSearching) {\n        // sortByRank is used to ensure stable sorting, as scores are non-unique\n        // this additionally ensures fuseOptions.sortFn is not ignored\n        choices.sort(sortByRank);\n      } else if (config.shouldSort) {\n        choices.sort(config.sorter);\n      }\n\n      let choiceLimit = choices.length;\n      choiceLimit = !withinGroup && renderLimit > 0 && choiceLimit > renderLimit ? renderLimit : choiceLimit;\n      choiceLimit--;\n\n      choices.every((choice, index) => {\n        // choiceEl being empty signals the contents has probably significantly changed\n        const dropdownItem =\n          choice.choiceEl ||\n          this._templates.choice(\n            config,\n            choice,\n            config.itemSelectText,\n            showLabel && choice.group ? choice.group.label : undefined,\n          );\n        choice.choiceEl = dropdownItem;\n        fragment.appendChild(dropdownItem);\n        if (isSearching || !choice.selected) {\n          selectableChoices = true;\n        } else if (!highlightedEl) {\n          highlightedEl = dropdownItem;\n        }\n\n        return index < choiceLimit;\n      });\n    };\n\n    if (activeChoices.length) {\n      if (config.resetScrollPosition) {\n        requestAnimationFrame(() => this.choiceList.scrollToTop());\n      }\n\n      if (!this._hasNonChoicePlaceholder && !isSearching && this._isSelectOneElement) {\n        // If we have a placeholder choice along with groups\n        renderChoices(\n          activeChoices.filter((choice) => choice.placeholder && !choice.group),\n          false,\n        );\n      }\n\n      // If we have grouped options\n      if (activeGroups.length && !isSearching) {\n        if (config.shouldSort) {\n          activeGroups.sort(config.sorter);\n        }\n        // render Choices without group first, regardless of sort, otherwise they won't be distinguishable\n        // from the last group\n        renderChoices(\n          activeChoices.filter((choice) => !choice.placeholder && !choice.group),\n          false,\n        );\n\n        activeGroups.forEach((group) => {\n          const groupChoices = renderableChoices(group.choices);\n          if (groupChoices.length) {\n            if (group.label) {\n              const dropdownGroup = group.groupEl || this._templates.choiceGroup(this.config, group);\n              group.groupEl = dropdownGroup;\n              dropdownGroup.remove();\n              fragment.appendChild(dropdownGroup);\n            }\n            renderChoices(groupChoices, true);\n          }\n        });\n      } else {\n        renderChoices(renderableChoices(activeChoices), false);\n      }\n    }\n\n    if (!selectableChoices && (isSearching || !fragment.children.length || !config.renderSelectedChoices)) {\n      if (!this._notice) {\n        this._notice = {\n          text: resolveStringFunction(isSearching ? config.noResultsText : config.noChoicesText),\n          type: isSearching ? NoticeTypes.noResults : NoticeTypes.noChoices,\n        };\n      }\n      fragment.replaceChildren('');\n    }\n\n    this._renderNotice(fragment);\n    this.choiceList.element.replaceChildren(fragment);\n\n    this._highlightChoice(highlightedEl);\n  }\n\n  _renderItems(): void {\n    const items = this._store.items || [];\n    const itemList = this.itemList.element;\n    const { config } = this;\n    const fragment: DocumentFragment = document.createDocumentFragment();\n\n    const itemFromList = (item: ChoiceFull): HTMLElement | null =>\n      itemList.querySelector<HTMLElement>(`[data-item][data-id=\"${item.id}\"]`);\n\n    const addItemToFragment = (item: ChoiceFull): void => {\n      let el = item.itemEl;\n      if (el && el.parentElement) {\n        return;\n      }\n      el = itemFromList(item) || this._templates.item(config, item, config.removeItemButton);\n      item.itemEl = el;\n      fragment.appendChild(el);\n    };\n\n    // new items\n    items.forEach(addItemToFragment);\n\n    let addedItems = !!fragment.childNodes.length;\n    if (this._isSelectOneElement) {\n      const existingItems = itemList.children.length;\n      if (addedItems || existingItems > 1) {\n        const placeholder = itemList.querySelector<HTMLElement>(getClassNamesSelector(config.classNames.placeholder));\n        if (placeholder) {\n          placeholder.remove();\n        }\n      } else if (!addedItems && !existingItems && this._placeholderValue) {\n        addedItems = true;\n        addItemToFragment(\n          mapInputToChoice<InputChoice>(\n            {\n              selected: true,\n              value: '',\n              label: this._placeholderValue,\n              placeholder: true,\n            },\n            false,\n          ),\n        );\n      }\n    }\n\n    if (addedItems) {\n      itemList.append(fragment);\n\n      if (config.shouldSortItems && !this._isSelectOneElement) {\n        items.sort(config.sorter);\n\n        // push sorting into the DOM\n        items.forEach((item) => {\n          const el = itemFromList(item);\n          if (el) {\n            el.remove();\n            fragment.append(el);\n          }\n        });\n\n        itemList.append(fragment);\n      }\n    }\n\n    if (this._isTextElement) {\n      // Update the value of the hidden input\n      this.passedElement.value = items.map(({ value }) => value).join(config.delimiter);\n    }\n  }\n\n  _displayNotice(text: string, type: NoticeType, openDropdown: boolean = true): void {\n    const oldNotice = this._notice;\n    if (\n      oldNotice &&\n      ((oldNotice.type === type && oldNotice.text === text) ||\n        (oldNotice.type === NoticeTypes.addChoice &&\n          (type === NoticeTypes.noResults || type === NoticeTypes.noChoices)))\n    ) {\n      if (openDropdown) {\n        this.showDropdown(true);\n      }\n\n      return;\n    }\n\n    this._clearNotice();\n\n    this._notice = text\n      ? {\n          text,\n          type,\n        }\n      : undefined;\n\n    this._renderNotice();\n\n    if (openDropdown && text) {\n      this.showDropdown(true);\n    }\n  }\n\n  _clearNotice(): void {\n    if (!this._notice) {\n      return;\n    }\n\n    const noticeElement = this.choiceList.element.querySelector<HTMLElement>(\n      getClassNamesSelector(this.config.classNames.notice),\n    );\n    if (noticeElement) {\n      noticeElement.remove();\n    }\n\n    this._notice = undefined;\n  }\n\n  _renderNotice(fragment?: DocumentFragment): void {\n    const noticeConf = this._notice;\n    if (noticeConf) {\n      const notice = this._templates.notice(this.config, noticeConf.text, noticeConf.type);\n      if (fragment) {\n        fragment.append(notice);\n      } else {\n        this.choiceList.prepend(notice);\n      }\n    }\n  }\n\n  /**\n   * @deprecated Use utils.getChoiceForOutput\n   */\n  // eslint-disable-next-line class-methods-use-this\n  _getChoiceForOutput(choice: ChoiceFull, keyCode?: number): EventChoice {\n    return getChoiceForOutput(choice, keyCode);\n  }\n\n  _triggerChange(value): void {\n    if (value === undefined || value === null) {\n      return;\n    }\n\n    this.passedElement.triggerEvent(EventType.change, {\n      value,\n    });\n  }\n\n  _handleButtonAction(element: HTMLElement): void {\n    const { items } = this._store;\n    if (!items.length || !this.config.removeItems || !this.config.removeItemButton) {\n      return;\n    }\n\n    const id = element && parseDataSetId(element.closest('[data-id]'));\n    const itemToRemove = id && items.find((item) => item.id === id);\n    if (!itemToRemove) {\n      return;\n    }\n\n    this._store.withTxn(() => {\n      // Remove item associated with button\n      this._removeItem(itemToRemove);\n      this._triggerChange(itemToRemove.value);\n\n      if (this._isSelectOneElement && !this._hasNonChoicePlaceholder) {\n        const placeholderChoice = (this.config.shouldSort ? this._store.choices.reverse() : this._store.choices).find(\n          (choice) => choice.placeholder,\n        );\n        if (placeholderChoice) {\n          this._addItem(placeholderChoice);\n          this.unhighlightAll();\n          if (placeholderChoice.value) {\n            this._triggerChange(placeholderChoice.value);\n          }\n        }\n      }\n    });\n  }\n\n  _handleItemAction(element: HTMLElement, hasShiftKey = false): void {\n    const { items } = this._store;\n    if (!items.length || !this.config.removeItems || this._isSelectOneElement) {\n      return;\n    }\n\n    const id = parseDataSetId(element);\n    if (!id) {\n      return;\n    }\n\n    // We only want to select one item with a click\n    // so we deselect any items that aren't the target\n    // unless shift is being pressed\n    items.forEach((item) => {\n      if (item.id === id && !item.highlighted) {\n        this.highlightItem(item);\n      } else if (!hasShiftKey && item.highlighted) {\n        this.unhighlightItem(item);\n      }\n    });\n\n    // Focus input as without focus, a user cannot do anything with a\n    // highlighted item\n    this.input.focus();\n  }\n\n  _handleChoiceAction(element: HTMLElement): boolean {\n    // If we are clicking on an option\n    const id = parseDataSetId(element);\n    const choice = id && this._store.getChoiceById(id);\n    if (!choice || choice.disabled) {\n      return false;\n    }\n\n    const hasActiveDropdown = this.dropdown.isActive;\n\n    if (!choice.selected) {\n      if (!this._canAddItems()) {\n        return true; // causes _onEnterKey to early out\n      }\n\n      this._store.withTxn(() => {\n        this._addItem(choice, true, true);\n\n        this.clearInput();\n        this.unhighlightAll();\n      });\n\n      this._triggerChange(choice.value);\n    }\n\n    // We want to close the dropdown if we are dealing with a single select box\n    if (hasActiveDropdown && this.config.closeDropdownOnSelect) {\n      this.hideDropdown(true);\n      this.containerOuter.element.focus();\n    }\n\n    return true;\n  }\n\n  _handleBackspace(items: ChoiceFull[]): void {\n    const { config } = this;\n    if (!config.removeItems || !items.length) {\n      return;\n    }\n\n    const lastItem = items[items.length - 1];\n    const hasHighlightedItems = items.some((item) => item.highlighted);\n\n    // If editing the last item is allowed and there are not other selected items,\n    // we can edit the item value. Otherwise if we can remove items, remove all selected items\n    if (config.editItems && !hasHighlightedItems && lastItem) {\n      this.input.value = lastItem.value;\n      this.input.setWidth();\n      this._removeItem(lastItem);\n      this._triggerChange(lastItem.value);\n    } else {\n      if (!hasHighlightedItems) {\n        // Highlight last item if none already highlighted\n        this.highlightItem(lastItem, false);\n      }\n      this.removeHighlightedItems(true);\n    }\n  }\n\n  _loadChoices(): void {\n    const { config } = this;\n    if (this._isTextElement) {\n      // Assign preset items from passed object first\n      this._presetChoices = config.items.map((e: InputChoice | string) => mapInputToChoice(e, false));\n      // Add any values passed from attribute\n      if (this.passedElement.value) {\n        const elementItems: ChoiceFull[] = this.passedElement.value\n          .split(config.delimiter)\n          .map((e: string) => mapInputToChoice<string>(e, false, this.config.allowHtmlUserInput));\n        this._presetChoices = this._presetChoices.concat(elementItems);\n      }\n      this._presetChoices.forEach((choice: ChoiceFull) => {\n        choice.selected = true;\n      });\n    } else if (this._isSelectElement) {\n      // Assign preset choices from passed object\n      this._presetChoices = config.choices.map((e: InputChoice) => mapInputToChoice(e, true));\n      // Create array of choices from option elements\n      const choicesFromOptions = (this.passedElement as WrappedSelect).optionsAsChoices();\n      if (choicesFromOptions) {\n        this._presetChoices.push(...choicesFromOptions);\n      }\n    }\n  }\n\n  _handleLoadingState(setLoading = true): void {\n    const el = this.itemList.element;\n    if (setLoading) {\n      this.disable();\n      this.containerOuter.addLoadingState();\n      if (this._isSelectOneElement) {\n        el.replaceChildren(this._templates.placeholder(this.config, this.config.loadingText));\n      } else {\n        this.input.placeholder = this.config.loadingText;\n      }\n    } else {\n      this.enable();\n      this.containerOuter.removeLoadingState();\n\n      if (this._isSelectOneElement) {\n        el.replaceChildren('');\n        this._render();\n      } else {\n        this.input.placeholder = this._placeholderValue || '';\n      }\n    }\n  }\n\n  _handleSearch(value?: string): void {\n    if (!this.input.isFocussed) {\n      return;\n    }\n\n    // Check that we have a value to search and the input was an alphanumeric character\n    if (value !== null && typeof value !== 'undefined' && value.length >= this.config.searchFloor) {\n      const resultCount = this.config.searchChoices ? this._searchChoices(value) : 0;\n      if (resultCount !== null) {\n        // Trigger search event\n        this.passedElement.triggerEvent(EventType.search, {\n          value,\n          resultCount,\n        });\n      }\n    } else if (this._store.choices.some((option) => !option.active)) {\n      this._stopSearch();\n    }\n  }\n\n  _canAddItems(): boolean {\n    const { config } = this;\n    const { maxItemCount, maxItemText } = config;\n\n    if (!config.singleModeForMultiSelect && maxItemCount > 0 && maxItemCount <= this._store.items.length) {\n      this.choiceList.element.replaceChildren('');\n      this._notice = undefined;\n      this._displayNotice(\n        typeof maxItemText === 'function' ? maxItemText(maxItemCount) : maxItemText,\n        NoticeTypes.addChoice,\n      );\n\n      return false;\n    }\n\n    if (this._notice && this._notice.type === NoticeTypes.addChoice) {\n      this._clearNotice();\n    }\n\n    return true;\n  }\n\n  _canCreateItem(value: string): boolean {\n    const { config } = this;\n    let canAddItem = true;\n    let notice = '';\n\n    if (canAddItem && typeof config.addItemFilter === 'function' && !config.addItemFilter(value)) {\n      canAddItem = false;\n      notice = resolveNoticeFunction(config.customAddItemText, value, undefined);\n    }\n\n    if (canAddItem) {\n      const foundChoice = this._store.choices.find((choice) => config.valueComparer(choice.value, value));\n      if (foundChoice) {\n        if (this._isSelectElement) {\n          // for exact matches, do not prompt to add it as a custom choice\n          this._displayNotice('', NoticeTypes.addChoice);\n\n          return false;\n        }\n        if (!config.duplicateItemsAllowed) {\n          canAddItem = false;\n          notice = resolveNoticeFunction(config.uniqueItemText, value, undefined);\n        }\n      }\n    }\n\n    if (canAddItem) {\n      notice = resolveNoticeFunction(config.addItemText, value, undefined);\n    }\n\n    if (notice) {\n      this._displayNotice(notice, NoticeTypes.addChoice);\n    }\n\n    return canAddItem;\n  }\n\n  _searchChoices(value: string): number | null {\n    const newValue = value.trim().replace(/\\s{2,}/, ' ');\n\n    // signal input didn't change search\n    if (!newValue.length || newValue === this._currentValue) {\n      return null;\n    }\n\n    const searcher = this._searcher;\n    if (searcher.isEmptyIndex()) {\n      searcher.index(this._store.searchableChoices);\n    }\n    // If new value matches the desired length and is not the same as the current value with a space\n    const results = searcher.search(newValue);\n\n    this._currentValue = newValue;\n    this._highlightPosition = 0;\n    this._isSearching = true;\n\n    const notice = this._notice;\n    const noticeType = notice && notice.type;\n    if (noticeType !== NoticeTypes.addChoice) {\n      if (!results.length) {\n        this._displayNotice(resolveStringFunction(this.config.noResultsText), NoticeTypes.noResults);\n      } else {\n        this._clearNotice();\n      }\n    }\n\n    this._store.dispatch(filterChoices(results));\n\n    return results.length;\n  }\n\n  _stopSearch(): void {\n    if (this._isSearching) {\n      this._currentValue = '';\n      this._isSearching = false;\n      this._clearNotice();\n      this._store.dispatch(activateChoices(true));\n\n      this.passedElement.triggerEvent(EventType.search, {\n        value: '',\n        resultCount: 0,\n      });\n    }\n  }\n\n  _addEventListeners(): void {\n    const documentElement = this._docRoot;\n    const outerElement = this.containerOuter.element;\n    const inputElement = this.input.element;\n    const passedElement = this.passedElement.element;\n\n    // capture events - can cancel event processing or propagation\n    documentElement.addEventListener('touchend', this._onTouchEnd, true);\n    outerElement.addEventListener('keydown', this._onKeyDown, true);\n    outerElement.addEventListener('mousedown', this._onMouseDown, true);\n\n    // passive events - doesn't call `preventDefault` or `stopPropagation`\n    documentElement.addEventListener('click', this._onClick, { passive: true });\n    documentElement.addEventListener('touchmove', this._onTouchMove, {\n      passive: true,\n    });\n    this.dropdown.element.addEventListener('mouseover', this._onMouseOver, {\n      passive: true,\n    });\n\n    if (this._isSelectOneElement) {\n      outerElement.addEventListener('focus', this._onFocus, {\n        passive: true,\n      });\n      outerElement.addEventListener('blur', this._onBlur, {\n        passive: true,\n      });\n    }\n\n    inputElement.addEventListener('keyup', this._onKeyUp, {\n      passive: true,\n    });\n    inputElement.addEventListener('input', this._onInput, {\n      passive: true,\n    });\n\n    inputElement.addEventListener('focus', this._onFocus, {\n      passive: true,\n    });\n    inputElement.addEventListener('blur', this._onBlur, {\n      passive: true,\n    });\n\n    if (inputElement.form) {\n      inputElement.form.addEventListener('reset', this._onFormReset, {\n        passive: true,\n      });\n    }\n\n    if (passedElement.hasAttribute('required')) {\n      passedElement.addEventListener('change', this._onChange, {\n        passive: true,\n      });\n\n      passedElement.addEventListener('invalid', this._onInvalid, {\n        passive: true,\n      });\n    }\n\n    this.input.addEventListeners();\n  }\n\n  _removeEventListeners(): void {\n    const documentElement = this._docRoot;\n    const outerElement = this.containerOuter.element;\n    const inputElement = this.input.element;\n    const passedElement = this.passedElement.element;\n\n    documentElement.removeEventListener('touchend', this._onTouchEnd, true);\n    outerElement.removeEventListener('keydown', this._onKeyDown, true);\n    outerElement.removeEventListener('mousedown', this._onMouseDown, true);\n\n    documentElement.removeEventListener('click', this._onClick);\n    documentElement.removeEventListener('touchmove', this._onTouchMove);\n    this.dropdown.element.removeEventListener('mouseover', this._onMouseOver);\n\n    if (this._isSelectOneElement) {\n      outerElement.removeEventListener('focus', this._onFocus);\n      outerElement.removeEventListener('blur', this._onBlur);\n    }\n\n    inputElement.removeEventListener('keyup', this._onKeyUp);\n    inputElement.removeEventListener('input', this._onInput);\n    inputElement.removeEventListener('focus', this._onFocus);\n    inputElement.removeEventListener('blur', this._onBlur);\n\n    if (inputElement.form) {\n      inputElement.form.removeEventListener('reset', this._onFormReset);\n    }\n\n    if (passedElement.hasAttribute('required')) {\n      passedElement.removeEventListener('change', this._onChange);\n      passedElement.removeEventListener('invalid', this._onInvalid);\n    }\n\n    this.input.removeEventListeners();\n  }\n\n  _onKeyDown(event: KeyboardEvent): void {\n    const { keyCode } = event;\n    const hasActiveDropdown = this.dropdown.isActive;\n    /*\n    See:\n    https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key\n    https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values\n    https://en.wikipedia.org/wiki/UTF-16#Code_points_from_U+010000_to_U+10FFFF - UTF-16 surrogate pairs\n    https://stackoverflow.com/a/70866532 - \"Unidentified\" for mobile\n    http://www.unicode.org/versions/Unicode5.2.0/ch16.pdf#G19635 - U+FFFF is reserved (Section 16.7)\n\n    Logic: when a key event is sent, `event.key` represents its printable value _or_ one\n    of a large list of special values indicating meta keys/functionality. In addition,\n    key events for compose functionality contain a value of `Dead` when mid-composition.\n\n    I can't quite verify it, but non-English IMEs may also be able to generate key codes\n    for code points in the surrogate-pair range, which could potentially be seen as having\n    key.length > 1. Since `Fn` is one of the special keys, we can't distinguish by that\n    alone.\n\n    Here, key.length === 1 means we know for sure the input was printable and not a special\n    `key` value. When the length is greater than 1, it could be either a printable surrogate\n    pair or a special `key` value. We can tell the difference by checking if the _character\n    code_ value (not code point!) is in the \"surrogate pair\" range or not.\n\n    We don't use .codePointAt because an invalid code point would return 65535, which wouldn't\n    pass the >= 0x10000 check we would otherwise use.\n\n    > ...The Unicode Standard sets aside 66 noncharacter code points. The last two code points\n    > of each plane are noncharacters: U+FFFE and U+FFFF on the BMP...\n    */\n    const wasPrintableChar =\n      event.key.length === 1 ||\n      (event.key.length === 2 && event.key.charCodeAt(0) >= 0xd800) ||\n      event.key === 'Unidentified';\n\n    /*\n      We do not show the dropdown if focusing out with esc or navigating through input fields.\n      An activated search can still be opened with any other key.\n     */\n    if (\n      !this._isTextElement &&\n      !hasActiveDropdown &&\n      keyCode !== KeyCodeMap.ESC_KEY &&\n      keyCode !== KeyCodeMap.TAB_KEY &&\n      keyCode !== KeyCodeMap.SHIFT_KEY\n    ) {\n      this.showDropdown();\n\n      if (!this.input.isFocussed && wasPrintableChar) {\n        /*\n          We update the input value with the pressed key as\n          the input was not focussed at the time of key press\n          therefore does not have the value of the key.\n        */\n        this.input.value += event.key;\n        // browsers interpret a space as pagedown\n        if (event.key === ' ') {\n          event.preventDefault();\n        }\n      }\n    }\n\n    switch (keyCode) {\n      case KeyCodeMap.A_KEY:\n        return this._onSelectKey(event, this.itemList.element.hasChildNodes());\n      case KeyCodeMap.ENTER_KEY:\n        return this._onEnterKey(event, hasActiveDropdown);\n      case KeyCodeMap.ESC_KEY:\n        return this._onEscapeKey(event, hasActiveDropdown);\n      case KeyCodeMap.UP_KEY:\n      case KeyCodeMap.PAGE_UP_KEY:\n      case KeyCodeMap.DOWN_KEY:\n      case KeyCodeMap.PAGE_DOWN_KEY:\n        return this._onDirectionKey(event, hasActiveDropdown);\n      case KeyCodeMap.DELETE_KEY:\n      case KeyCodeMap.BACK_KEY:\n        return this._onDeleteKey(event, this._store.items, this.input.isFocussed);\n      default:\n    }\n  }\n\n  _onKeyUp(/* event: KeyboardEvent */): void {\n    this._canSearch = this.config.searchEnabled;\n  }\n\n  _onInput(/* event: InputEvent */): void {\n    const { value } = this.input;\n    if (!value) {\n      if (this._isTextElement) {\n        this.hideDropdown(true);\n      } else {\n        this._stopSearch();\n      }\n\n      return;\n    }\n\n    if (!this._canAddItems()) {\n      return;\n    }\n\n    if (this._canSearch) {\n      // do the search even if the entered text can not be added\n      this._handleSearch(value);\n    }\n\n    if (!this._canAddUserChoices) {\n      return;\n    }\n\n    // determine if a notice needs to be displayed for why a search result can't be added\n    this._canCreateItem(value);\n    if (this._isSelectElement) {\n      this._highlightPosition = 0; // reset to select the notice and/or exact match\n      this._highlightChoice();\n    }\n  }\n\n  _onSelectKey(event: KeyboardEvent, hasItems: boolean): void {\n    // If CTRL + A or CMD + A have been pressed and there are items to select\n    if ((event.ctrlKey || event.metaKey) && hasItems) {\n      this._canSearch = false;\n\n      const shouldHightlightAll =\n        this.config.removeItems && !this.input.value && this.input.element === document.activeElement;\n\n      if (shouldHightlightAll) {\n        this.highlightAll();\n      }\n    }\n  }\n\n  _onEnterKey(event: KeyboardEvent, hasActiveDropdown: boolean): void {\n    const { value } = this.input;\n    const target = event.target as HTMLElement | null;\n    event.preventDefault();\n\n    if (target && target.hasAttribute('data-button')) {\n      this._handleButtonAction(target);\n\n      return;\n    }\n\n    if (!hasActiveDropdown) {\n      if (this._isSelectElement || this._notice) {\n        this.showDropdown();\n      }\n\n      return;\n    }\n\n    const highlightedChoice = this.dropdown.element.querySelector<HTMLElement>(\n      getClassNamesSelector(this.config.classNames.highlightedState),\n    );\n\n    if (highlightedChoice && this._handleChoiceAction(highlightedChoice)) {\n      return;\n    }\n\n    if (!target || !value) {\n      this.hideDropdown(true);\n\n      return;\n    }\n\n    if (!this._canAddItems()) {\n      return;\n    }\n\n    let addedItem = false;\n    this._store.withTxn(() => {\n      addedItem = this._findAndSelectChoiceByValue(value, true);\n      if (!addedItem) {\n        if (!this._canAddUserChoices) {\n          return;\n        }\n\n        if (!this._canCreateItem(value)) {\n          return;\n        }\n\n        this._addChoice(mapInputToChoice<string>(value, false, this.config.allowHtmlUserInput), true, true);\n        addedItem = true;\n      }\n\n      this.clearInput();\n      this.unhighlightAll();\n    });\n\n    if (!addedItem) {\n      return;\n    }\n\n    this._triggerChange(value);\n\n    if (this.config.closeDropdownOnSelect) {\n      this.hideDropdown(true);\n    }\n  }\n\n  _onEscapeKey(event: KeyboardEvent, hasActiveDropdown: boolean): void {\n    if (hasActiveDropdown) {\n      event.stopPropagation();\n      this.hideDropdown(true);\n      this._stopSearch();\n      this.containerOuter.element.focus();\n    }\n  }\n\n  _onDirectionKey(event: KeyboardEvent, hasActiveDropdown: boolean): void {\n    const { keyCode } = event;\n\n    // If up or down key is pressed, traverse through options\n    if (hasActiveDropdown || this._isSelectOneElement) {\n      this.showDropdown();\n      this._canSearch = false;\n\n      const directionInt = keyCode === KeyCodeMap.DOWN_KEY || keyCode === KeyCodeMap.PAGE_DOWN_KEY ? 1 : -1;\n      const skipKey = event.metaKey || keyCode === KeyCodeMap.PAGE_DOWN_KEY || keyCode === KeyCodeMap.PAGE_UP_KEY;\n\n      let nextEl: HTMLElement | null;\n      if (skipKey) {\n        if (directionInt > 0) {\n          nextEl = this.dropdown.element.querySelector(`${selectableChoiceIdentifier}:last-of-type`);\n        } else {\n          nextEl = this.dropdown.element.querySelector(selectableChoiceIdentifier);\n        }\n      } else {\n        const currentEl = this.dropdown.element.querySelector<HTMLElement>(\n          getClassNamesSelector(this.config.classNames.highlightedState),\n        );\n        if (currentEl) {\n          nextEl = getAdjacentEl(currentEl, selectableChoiceIdentifier, directionInt);\n        } else {\n          nextEl = this.dropdown.element.querySelector(selectableChoiceIdentifier);\n        }\n      }\n\n      if (nextEl) {\n        // We prevent default to stop the cursor moving\n        // when pressing the arrow\n        if (!isScrolledIntoView(nextEl, this.choiceList.element, directionInt)) {\n          this.choiceList.scrollToChildElement(nextEl, directionInt);\n        }\n        this._highlightChoice(nextEl);\n      }\n\n      // Prevent default to maintain cursor position whilst\n      // traversing dropdown options\n      event.preventDefault();\n    }\n  }\n\n  _onDeleteKey(event: KeyboardEvent, items: ChoiceFull[], hasFocusedInput: boolean): void {\n    // If backspace or delete key is pressed and the input has no value\n    if (!this._isSelectOneElement && !(event.target as HTMLInputElement).value && hasFocusedInput) {\n      this._handleBackspace(items);\n      event.preventDefault();\n    }\n  }\n\n  _onTouchMove(): void {\n    if (this._wasTap) {\n      this._wasTap = false;\n    }\n  }\n\n  _onTouchEnd(event: TouchEvent): void {\n    const { target } = event || (event as TouchEvent).touches[0];\n    const touchWasWithinContainer = this._wasTap && this.containerOuter.element.contains(target as Node);\n\n    if (touchWasWithinContainer) {\n      const containerWasExactTarget = target === this.containerOuter.element || target === this.containerInner.element;\n\n      if (containerWasExactTarget) {\n        if (this._isTextElement) {\n          this.input.focus();\n        } else if (this._isSelectMultipleElement) {\n          this.showDropdown();\n        }\n      }\n\n      // Prevents focus event firing\n      event.stopPropagation();\n    }\n\n    this._wasTap = true;\n  }\n\n  /**\n   * Handles mousedown event in capture mode for containetOuter.element\n   */\n  _onMouseDown(event: MouseEvent): void {\n    const { target } = event;\n    if (!(target instanceof Element)) {\n      return;\n    }\n\n    // If we have our mouse down on the scrollbar and are on IE11...\n    if (IS_IE11 && this.choiceList.element.contains(target)) {\n      // check if click was on a scrollbar area\n      const firstChoice = this.choiceList.element.firstElementChild as HTMLElement;\n\n      this._isScrollingOnIe =\n        this._direction === 'ltr' ? event.offsetX >= firstChoice.offsetWidth : event.offsetX < firstChoice.offsetLeft;\n    }\n\n    if (target === this.input.element) {\n      return;\n    }\n\n    const item = target.closest('[data-button],[data-item],[data-choice]');\n    if (item instanceof HTMLElement) {\n      if ('button' in item.dataset) {\n        this._handleButtonAction(item);\n      } else if ('item' in item.dataset) {\n        this._handleItemAction(item, event.shiftKey);\n      } else if ('choice' in item.dataset) {\n        this._handleChoiceAction(item);\n      }\n    }\n\n    event.preventDefault();\n  }\n\n  /**\n   * Handles mouseover event over this.dropdown\n   * @param {MouseEvent} event\n   */\n  _onMouseOver({ target }: Pick<MouseEvent, 'target'>): void {\n    if (target instanceof HTMLElement && 'choice' in target.dataset) {\n      this._highlightChoice(target);\n    }\n  }\n\n  _onClick({ target }: Pick<MouseEvent, 'target'>): void {\n    const { containerOuter } = this;\n    const clickWasWithinContainer = containerOuter.element.contains(target as Node);\n\n    if (clickWasWithinContainer) {\n      if (!this.dropdown.isActive && !containerOuter.isDisabled) {\n        if (this._isTextElement) {\n          if (document.activeElement !== this.input.element) {\n            this.input.focus();\n          }\n        } else {\n          this.showDropdown();\n          containerOuter.element.focus();\n        }\n      } else if (\n        this._isSelectOneElement &&\n        target !== this.input.element &&\n        !this.dropdown.element.contains(target as Node)\n      ) {\n        this.hideDropdown();\n      }\n    } else {\n      containerOuter.removeFocusState();\n      this.hideDropdown(true);\n      this.unhighlightAll();\n    }\n  }\n\n  _onFocus({ target }: Pick<FocusEvent, 'target'>): void {\n    const { containerOuter } = this;\n    const focusWasWithinContainer = target && containerOuter.element.contains(target as Node);\n\n    if (!focusWasWithinContainer) {\n      return;\n    }\n    const targetIsInput = target === this.input.element;\n    if (this._isTextElement) {\n      if (targetIsInput) {\n        containerOuter.addFocusState();\n      }\n    } else if (this._isSelectMultipleElement) {\n      if (targetIsInput) {\n        this.showDropdown(true);\n        // If element is a select box, the focused element is the container and the dropdown\n        // isn't already open, focus and show dropdown\n        containerOuter.addFocusState();\n      }\n    } else {\n      containerOuter.addFocusState();\n      if (targetIsInput) {\n        this.showDropdown(true);\n      }\n    }\n  }\n\n  _onBlur({ target }: Pick<FocusEvent, 'target'>): void {\n    const { containerOuter } = this;\n    const blurWasWithinContainer = target && containerOuter.element.contains(target as Node);\n\n    if (blurWasWithinContainer && !this._isScrollingOnIe) {\n      if (target === this.input.element) {\n        containerOuter.removeFocusState();\n        this.hideDropdown(true);\n        if (this._isTextElement || this._isSelectMultipleElement) {\n          this.unhighlightAll();\n        }\n      } else if (target === this.containerOuter.element) {\n        // Remove the focus state when the past outerContainer was the target\n        containerOuter.removeFocusState();\n\n        // Also close the dropdown if search is disabled\n        if (!this.config.searchEnabled) {\n          this.hideDropdown(true);\n        }\n      }\n    } else {\n      // On IE11, clicking the scollbar blurs our input and thus\n      // closes the dropdown. To stop this, we refocus our input\n      // if we know we are on IE *and* are scrolling.\n      this._isScrollingOnIe = false;\n      this.input.element.focus();\n    }\n  }\n\n  _onFormReset(): void {\n    this._store.withTxn(() => {\n      this.clearInput();\n      this.hideDropdown();\n      this.refresh(false, false, true);\n      if (this._initialItems.length) {\n        this.setChoiceByValue(this._initialItems);\n      }\n    });\n  }\n\n  _onChange(event: Event & { target: HTMLInputElement | HTMLSelectElement }): void {\n    if (!event.target.checkValidity()) {\n      return;\n    }\n\n    this.containerOuter.removeInvalidState();\n  }\n\n  _onInvalid(): void {\n    this.containerOuter.addInvalidState();\n  }\n\n  /**\n   * Removes any highlighted choice options\n   */\n  _removeHighlightedChoices(): void {\n    const { highlightedState } = this.config.classNames;\n    const highlightedChoices = Array.from(\n      this.dropdown.element.querySelectorAll<HTMLElement>(getClassNamesSelector(highlightedState)),\n    );\n\n    // Remove any highlighted choices\n    highlightedChoices.forEach((choice) => {\n      removeClassesFromElement(choice, highlightedState);\n      choice.setAttribute('aria-selected', 'false');\n    });\n  }\n\n  _highlightChoice(el: HTMLElement | null = null): void {\n    const choices = Array.from(this.dropdown.element.querySelectorAll<HTMLElement>(selectableChoiceIdentifier));\n\n    if (!choices.length) {\n      return;\n    }\n\n    let passedEl = el;\n    const { highlightedState } = this.config.classNames;\n\n    this._removeHighlightedChoices();\n\n    if (passedEl) {\n      this._highlightPosition = choices.indexOf(passedEl);\n    } else {\n      // Highlight choice based on last known highlight location\n      if (choices.length > this._highlightPosition) {\n        // If we have an option to highlight\n        passedEl = choices[this._highlightPosition];\n      } else {\n        // Otherwise highlight the option before\n        passedEl = choices[choices.length - 1];\n      }\n\n      if (!passedEl) {\n        passedEl = choices[0];\n      }\n    }\n\n    addClassesToElement(passedEl, highlightedState);\n    passedEl.setAttribute('aria-selected', 'true');\n    this.passedElement.triggerEvent(EventType.highlightChoice, {\n      el: passedEl,\n    });\n\n    if (this.dropdown.isActive) {\n      // IE11 ignores aria-label and blocks virtual keyboard\n      // if aria-activedescendant is set without a dropdown\n      this.input.setActiveDescendant(passedEl.id);\n      this.containerOuter.setActiveDescendant(passedEl.id);\n    }\n  }\n\n  _addItem(item: ChoiceFull, withEvents: boolean = true, userTriggered = false): void {\n    if (!item.id) {\n      throw new TypeError('item.id must be set before _addItem is called for a choice/item');\n    }\n\n    if (this.config.singleModeForMultiSelect || this._isSelectOneElement) {\n      this.removeActiveItems(item.id);\n    }\n\n    this._store.dispatch(addItem(item));\n\n    if (withEvents) {\n      const eventChoice = getChoiceForOutput(item);\n      this.passedElement.triggerEvent(EventType.addItem, eventChoice);\n\n      if (userTriggered) {\n        this.passedElement.triggerEvent(EventType.choice, eventChoice);\n      }\n    }\n  }\n\n  _removeItem(item: ChoiceFull): void {\n    if (!item.id) {\n      return;\n    }\n\n    this._store.dispatch(removeItem(item));\n    const notice = this._notice;\n    if (notice && notice.type === NoticeTypes.noChoices) {\n      this._clearNotice();\n    }\n\n    this.passedElement.triggerEvent(EventType.removeItem, getChoiceForOutput(item));\n  }\n\n  _addChoice(choice: ChoiceFull, withEvents: boolean = true, userTriggered = false): void {\n    if (choice.id) {\n      throw new TypeError('Can not re-add a choice which has already been added');\n    }\n\n    const { config } = this;\n    if (!config.duplicateItemsAllowed && this._store.choices.find((c) => config.valueComparer(c.value, choice.value))) {\n      return;\n    }\n\n    // Generate unique id, in-place update is required so chaining _addItem works as expected\n    this._lastAddedChoiceId++;\n    choice.id = this._lastAddedChoiceId;\n    choice.elementId = `${this._baseId}-${this._idNames.itemChoice}-${choice.id}`;\n\n    const { prependValue, appendValue } = config;\n    if (prependValue) {\n      choice.value = prependValue + choice.value;\n    }\n    if (appendValue) {\n      choice.value += appendValue.toString();\n    }\n    if ((prependValue || appendValue) && choice.element) {\n      (choice.element as HTMLOptionElement).value = choice.value;\n    }\n\n    this._clearNotice();\n    this._store.dispatch(addChoice(choice));\n\n    if (choice.selected) {\n      this._addItem(choice, withEvents, userTriggered);\n    }\n  }\n\n  _addGroup(group: GroupFull, withEvents: boolean = true): void {\n    if (group.id) {\n      throw new TypeError('Can not re-add a group which has already been added');\n    }\n\n    this._store.dispatch(addGroup(group));\n\n    if (!group.choices) {\n      return;\n    }\n\n    // add unique id for the group(s), and do not store the full list of choices in this group\n    this._lastAddedGroupId++;\n    group.id = this._lastAddedGroupId;\n\n    group.choices.forEach((item: ChoiceFull) => {\n      item.group = group;\n      if (group.disabled) {\n        item.disabled = true;\n      }\n\n      this._addChoice(item, withEvents);\n    });\n  }\n\n  _createTemplates(): void {\n    const { callbackOnCreateTemplates } = this.config;\n    let userTemplates: Partial<Templates> = {};\n\n    if (typeof callbackOnCreateTemplates === 'function') {\n      userTemplates = callbackOnCreateTemplates.call(this, strToEl, escapeForTemplate, getClassNames);\n    }\n\n    const templating: Partial<Templates> = {};\n    Object.keys(this._templates).forEach((name) => {\n      if (name in userTemplates) {\n        templating[name] = userTemplates[name].bind(this);\n      } else {\n        templating[name] = this._templates[name].bind(this);\n      }\n    });\n\n    this._templates = templating as Templates;\n  }\n\n  _createElements(): void {\n    const templating = this._templates;\n    const { config, _isSelectOneElement: isSelectOneElement } = this;\n    const { position, classNames } = config;\n    const elementType = this._elementType;\n\n    this.containerOuter = new Container({\n      element: templating.containerOuter(\n        config,\n        this._direction,\n        this._isSelectElement,\n        isSelectOneElement,\n        config.searchEnabled,\n        elementType,\n        config.labelId,\n      ),\n      classNames,\n      type: elementType,\n      position,\n    });\n\n    this.containerInner = new Container({\n      element: templating.containerInner(config),\n      classNames,\n      type: elementType,\n      position,\n    });\n\n    this.input = new Input({\n      element: templating.input(config, this._placeholderValue),\n      classNames,\n      type: elementType,\n      preventPaste: !config.paste,\n    });\n\n    this.choiceList = new List({\n      element: templating.choiceList(config, isSelectOneElement),\n    });\n\n    this.itemList = new List({\n      element: templating.itemList(config, isSelectOneElement),\n    });\n\n    this.dropdown = new Dropdown({\n      element: templating.dropdown(config),\n      classNames,\n      type: elementType,\n    });\n  }\n\n  _createStructure(): void {\n    const { containerInner, containerOuter, passedElement } = this;\n    const dropdownElement = this.dropdown.element;\n\n    // Hide original element\n    passedElement.conceal();\n    // Wrap input in container preserving DOM ordering\n    containerInner.wrap(passedElement.element);\n    // Wrapper inner container with outer container\n    containerOuter.wrap(containerInner.element);\n\n    containerOuter.element.appendChild(containerInner.element);\n    containerOuter.element.appendChild(dropdownElement);\n    containerInner.element.appendChild(this.itemList.element);\n    dropdownElement.appendChild(this.choiceList.element);\n\n    if (this._isSelectOneElement) {\n      this.input.placeholder = this.config.searchPlaceholderValue || '';\n      if (this.config.searchEnabled) {\n        dropdownElement.insertBefore(this.input.element, dropdownElement.firstChild);\n      }\n    } else {\n      if (!this._isSelectMultipleElement || this.config.searchEnabled) {\n        containerInner.element.appendChild(this.input.element);\n      }\n      if (this._placeholderValue) {\n        this.input.placeholder = this._placeholderValue;\n      }\n      this.input.setWidth();\n    }\n\n    this._highlightPosition = 0;\n    this._isSearching = false;\n  }\n\n  _initStore(): void {\n    this._store.subscribe(this._render).withTxn(() => {\n      this._addPredefinedChoices(\n        this._presetChoices,\n        this._isSelectOneElement && !this._hasNonChoicePlaceholder,\n        false,\n      );\n    });\n\n    if (!this._store.choices.length || (this._isSelectOneElement && this._hasNonChoicePlaceholder)) {\n      this._render();\n    }\n  }\n\n  _addPredefinedChoices(\n    choices: (ChoiceFull | GroupFull)[],\n    selectFirstOption: boolean = false,\n    withEvents: boolean = true,\n  ): void {\n    if (selectFirstOption) {\n      /**\n       * If there is a selected choice already or the choice is not the first in\n       * the array, add each choice normally.\n       *\n       * Otherwise we pre-select the first enabled choice in the array (\"select-one\" only)\n       */\n      const noSelectedChoices = choices.findIndex((choice: ChoiceFull) => choice.selected) === -1;\n      if (noSelectedChoices) {\n        choices.some((choice) => {\n          if (choice.disabled || 'choices' in choice) {\n            return false;\n          }\n\n          choice.selected = true;\n\n          return true;\n        });\n      }\n    }\n\n    choices.forEach((item) => {\n      if ('choices' in item) {\n        if (this._isSelectElement) {\n          this._addGroup(item, withEvents);\n        }\n      } else {\n        this._addChoice(item, withEvents);\n      }\n    });\n  }\n\n  _findAndSelectChoiceByValue(value: string, userTriggered: boolean = false): boolean {\n    // Check 'value' property exists and the choice isn't already selected\n    const foundChoice = this._store.choices.find((choice) => this.config.valueComparer(choice.value, value));\n\n    if (foundChoice && !foundChoice.disabled && !foundChoice.selected) {\n      this._addItem(foundChoice, true, userTriggered);\n\n      return true;\n    }\n\n    return false;\n  }\n\n  _generatePlaceholderValue(): string | null {\n    const { config } = this;\n    if (!config.placeholder) {\n      return null;\n    }\n\n    if (this._hasNonChoicePlaceholder) {\n      return config.placeholderValue;\n    }\n\n    if (this._isSelectElement) {\n      const { placeholderOption } = this.passedElement as WrappedSelect;\n\n      return placeholderOption ? placeholderOption.text : null;\n    }\n\n    return null;\n  }\n\n  _warnChoicesInitFailed(caller: string): void {\n    if (this.config.silent) {\n      return;\n    }\n    if (!this.initialised) {\n      throw new TypeError(`${caller} called on a non-initialised instance of Choices`);\n    } else if (!this.initialisedOK) {\n      throw new TypeError(`${caller} called for an element which has multiple instances of Choices initialised on it`);\n    }\n  }\n}\n\nexport default Choices;\n"
  },
  {
    "path": "src/scripts/components/container.ts",
    "content": "import { addClassesToElement, removeClassesFromElement } from '../lib/utils';\nimport { ClassNames } from '../interfaces/class-names';\nimport { PositionOptionsType } from '../interfaces/position-options-type';\nimport { PassedElementType, PassedElementTypes } from '../interfaces/passed-element-type';\n\nexport default class Container {\n  element: HTMLElement;\n\n  type: PassedElementType;\n\n  classNames: ClassNames;\n\n  position: PositionOptionsType;\n\n  isOpen: boolean;\n\n  isFlipped: boolean;\n\n  isDisabled: boolean;\n\n  isLoading: boolean;\n\n  constructor({\n    element,\n    type,\n    classNames,\n    position,\n  }: {\n    element: HTMLElement;\n    type: PassedElementType;\n    classNames: ClassNames;\n    position: PositionOptionsType;\n  }) {\n    this.element = element;\n    this.classNames = classNames;\n    this.type = type;\n    this.position = position;\n    this.isOpen = false;\n    this.isFlipped = false;\n    this.isDisabled = false;\n    this.isLoading = false;\n  }\n\n  /**\n   * Determine whether container should be flipped based on passed\n   * dropdown position\n   */\n  shouldFlip(dropdownPos: number, dropdownHeight: number): boolean {\n    // If flip is enabled and the dropdown bottom position is\n    // greater than the window height flip the dropdown.\n    let shouldFlip = false;\n    if (this.position === 'auto') {\n      shouldFlip =\n        this.element.getBoundingClientRect().top - dropdownHeight >= 0 &&\n        !window.matchMedia(`(min-height: ${dropdownPos + 1}px)`).matches;\n    } else if (this.position === 'top') {\n      shouldFlip = true;\n    }\n\n    return shouldFlip;\n  }\n\n  setActiveDescendant(activeDescendantID: string): void {\n    this.element.setAttribute('aria-activedescendant', activeDescendantID);\n  }\n\n  removeActiveDescendant(): void {\n    this.element.removeAttribute('aria-activedescendant');\n  }\n\n  open(dropdownPos: number, dropdownHeight: number): void {\n    addClassesToElement(this.element, this.classNames.openState);\n    this.element.setAttribute('aria-expanded', 'true');\n    this.isOpen = true;\n\n    if (this.shouldFlip(dropdownPos, dropdownHeight)) {\n      addClassesToElement(this.element, this.classNames.flippedState);\n      this.isFlipped = true;\n    }\n  }\n\n  close(): void {\n    removeClassesFromElement(this.element, this.classNames.openState);\n    this.element.setAttribute('aria-expanded', 'false');\n    this.removeActiveDescendant();\n    this.isOpen = false;\n\n    // A dropdown flips if it does not have space within the page\n    if (this.isFlipped) {\n      removeClassesFromElement(this.element, this.classNames.flippedState);\n      this.isFlipped = false;\n    }\n  }\n\n  addFocusState(): void {\n    addClassesToElement(this.element, this.classNames.focusState);\n  }\n\n  removeFocusState(): void {\n    removeClassesFromElement(this.element, this.classNames.focusState);\n  }\n\n  addInvalidState(): void {\n    addClassesToElement(this.element, this.classNames.invalidState);\n  }\n\n  removeInvalidState(): void {\n    removeClassesFromElement(this.element, this.classNames.invalidState);\n  }\n\n  enable(): void {\n    removeClassesFromElement(this.element, this.classNames.disabledState);\n    this.element.removeAttribute('aria-disabled');\n    if (this.type === PassedElementTypes.SelectOne) {\n      this.element.setAttribute('tabindex', '0');\n    }\n    this.isDisabled = false;\n  }\n\n  disable(): void {\n    addClassesToElement(this.element, this.classNames.disabledState);\n    this.element.setAttribute('aria-disabled', 'true');\n    if (this.type === PassedElementTypes.SelectOne) {\n      this.element.setAttribute('tabindex', '-1');\n    }\n    this.isDisabled = true;\n  }\n\n  wrap(element: HTMLElement): void {\n    const el = this.element;\n    const { parentNode } = element;\n    if (parentNode) {\n      if (element.nextSibling) {\n        parentNode.insertBefore(el, element.nextSibling);\n      } else {\n        parentNode.appendChild(el);\n      }\n    }\n\n    el.appendChild(element);\n  }\n\n  unwrap(element: HTMLElement): void {\n    const el = this.element;\n    const { parentNode } = el;\n    if (parentNode) {\n      // Move passed element outside this element\n      parentNode.insertBefore(element, el);\n      // Remove this element\n      parentNode.removeChild(el);\n    }\n  }\n\n  addLoadingState(): void {\n    addClassesToElement(this.element, this.classNames.loadingState);\n    this.element.setAttribute('aria-busy', 'true');\n    this.isLoading = true;\n  }\n\n  removeLoadingState(): void {\n    removeClassesFromElement(this.element, this.classNames.loadingState);\n    this.element.removeAttribute('aria-busy');\n    this.isLoading = false;\n  }\n}\n"
  },
  {
    "path": "src/scripts/components/dropdown.ts",
    "content": "import { ClassNames } from '../interfaces/class-names';\nimport { PassedElementType } from '../interfaces/passed-element-type';\nimport { addClassesToElement, removeClassesFromElement } from '../lib/utils';\n\nexport default class Dropdown {\n  element: HTMLElement;\n\n  type: PassedElementType;\n\n  classNames: ClassNames;\n\n  isActive: boolean;\n\n  constructor({\n    element,\n    type,\n    classNames,\n  }: {\n    element: HTMLElement;\n    type: PassedElementType;\n    classNames: ClassNames;\n  }) {\n    this.element = element;\n    this.classNames = classNames;\n    this.type = type;\n    this.isActive = false;\n  }\n\n  /**\n   * Show dropdown to user by adding active state class\n   */\n  show(): this {\n    addClassesToElement(this.element, this.classNames.activeState);\n    this.element.setAttribute('aria-expanded', 'true');\n    this.isActive = true;\n\n    return this;\n  }\n\n  /**\n   * Hide dropdown from user\n   */\n  hide(): this {\n    removeClassesFromElement(this.element, this.classNames.activeState);\n    this.element.setAttribute('aria-expanded', 'false');\n    this.isActive = false;\n\n    return this;\n  }\n}\n"
  },
  {
    "path": "src/scripts/components/index.ts",
    "content": "import Dropdown from './dropdown';\nimport Container from './container';\nimport Input from './input';\nimport List from './list';\nimport WrappedInput from './wrapped-input';\nimport WrappedSelect from './wrapped-select';\n\nexport { Dropdown, Container, Input, List, WrappedInput, WrappedSelect };\n"
  },
  {
    "path": "src/scripts/components/input.ts",
    "content": "import { ClassNames } from '../interfaces/class-names';\nimport { PassedElementType, PassedElementTypes } from '../interfaces/passed-element-type';\n\nexport default class Input {\n  element: HTMLInputElement;\n\n  type: PassedElementType;\n\n  classNames: ClassNames;\n\n  preventPaste: boolean;\n\n  isFocussed: boolean;\n\n  isDisabled: boolean;\n\n  constructor({\n    element,\n    type,\n    classNames,\n    preventPaste,\n  }: {\n    element: HTMLInputElement;\n    type: PassedElementType;\n    classNames: ClassNames;\n    preventPaste: boolean;\n  }) {\n    this.element = element;\n    this.type = type;\n    this.classNames = classNames;\n    this.preventPaste = preventPaste;\n\n    this.isFocussed = this.element.isEqualNode(document.activeElement);\n    this.isDisabled = element.disabled;\n    this._onPaste = this._onPaste.bind(this);\n    this._onInput = this._onInput.bind(this);\n    this._onFocus = this._onFocus.bind(this);\n    this._onBlur = this._onBlur.bind(this);\n  }\n\n  set placeholder(placeholder: string) {\n    this.element.placeholder = placeholder;\n  }\n\n  get value(): string {\n    return this.element.value;\n  }\n\n  set value(value: string) {\n    this.element.value = value;\n  }\n\n  addEventListeners(): void {\n    const el = this.element;\n    el.addEventListener('paste', this._onPaste);\n    el.addEventListener('input', this._onInput, {\n      passive: true,\n    });\n    el.addEventListener('focus', this._onFocus, {\n      passive: true,\n    });\n    el.addEventListener('blur', this._onBlur, {\n      passive: true,\n    });\n  }\n\n  removeEventListeners(): void {\n    const el = this.element;\n    el.removeEventListener('input', this._onInput);\n    el.removeEventListener('paste', this._onPaste);\n    el.removeEventListener('focus', this._onFocus);\n    el.removeEventListener('blur', this._onBlur);\n  }\n\n  enable(): void {\n    const el = this.element;\n    el.removeAttribute('disabled');\n    this.isDisabled = false;\n  }\n\n  disable(): void {\n    const el = this.element;\n    el.setAttribute('disabled', '');\n    this.isDisabled = true;\n  }\n\n  focus(): void {\n    if (!this.isFocussed) {\n      this.element.focus();\n    }\n  }\n\n  blur(): void {\n    if (this.isFocussed) {\n      this.element.blur();\n    }\n  }\n\n  clear(setWidth = true): this {\n    this.element.value = '';\n    if (setWidth) {\n      this.setWidth();\n    }\n\n    return this;\n  }\n\n  /**\n   * Set the correct input width based on placeholder\n   * value or input value\n   */\n  setWidth(): void {\n    // Resize input to contents or placeholder\n    const { element } = this;\n    element.style.minWidth = `${element.placeholder.length + 1}ch`;\n    element.style.width = `${element.value.length + 1}ch`;\n  }\n\n  setActiveDescendant(activeDescendantID: string): void {\n    this.element.setAttribute('aria-activedescendant', activeDescendantID);\n  }\n\n  removeActiveDescendant(): void {\n    this.element.removeAttribute('aria-activedescendant');\n  }\n\n  _onInput(): void {\n    if (this.type !== PassedElementTypes.SelectOne) {\n      this.setWidth();\n    }\n  }\n\n  _onPaste(event: ClipboardEvent): void {\n    if (this.preventPaste) {\n      event.preventDefault();\n    }\n  }\n\n  _onFocus(): void {\n    this.isFocussed = true;\n  }\n\n  _onBlur(): void {\n    this.isFocussed = false;\n  }\n}\n"
  },
  {
    "path": "src/scripts/components/list.ts",
    "content": "import { SCROLLING_SPEED } from '../constants';\n\nexport default class List {\n  element: HTMLElement;\n\n  scrollPos: number;\n\n  height: number;\n\n  constructor({ element }: { element: HTMLElement }) {\n    this.element = element;\n    this.scrollPos = this.element.scrollTop;\n    this.height = this.element.offsetHeight;\n  }\n\n  prepend(node: Element | DocumentFragment): void {\n    const child = this.element.firstElementChild;\n    if (child) {\n      this.element.insertBefore(node, child);\n    } else {\n      this.element.append(node);\n    }\n  }\n\n  scrollToTop(): void {\n    this.element.scrollTop = 0;\n  }\n\n  scrollToChildElement(element: HTMLElement, direction: 1 | -1): void {\n    if (!element) {\n      return;\n    }\n\n    const listHeight = this.element.offsetHeight;\n    // Scroll position of dropdown\n    const listScrollPosition = this.element.scrollTop + listHeight;\n\n    const elementHeight = element.offsetHeight;\n    // Distance from bottom of element to top of parent\n    const elementPos = element.offsetTop + elementHeight;\n\n    // Difference between the element and scroll position\n    const destination = direction > 0 ? this.element.scrollTop + elementPos - listScrollPosition : element.offsetTop;\n\n    requestAnimationFrame(() => {\n      this._animateScroll(destination, direction);\n    });\n  }\n\n  _scrollDown(scrollPos: number, strength: number, destination: number): void {\n    const easing = (destination - scrollPos) / strength;\n    const distance = easing > 1 ? easing : 1;\n\n    this.element.scrollTop = scrollPos + distance;\n  }\n\n  _scrollUp(scrollPos: number, strength: number, destination: number): void {\n    const easing = (scrollPos - destination) / strength;\n    const distance = easing > 1 ? easing : 1;\n\n    this.element.scrollTop = scrollPos - distance;\n  }\n\n  _animateScroll(destination: number, direction: number): void {\n    const strength = SCROLLING_SPEED;\n    const choiceListScrollTop = this.element.scrollTop;\n    let continueAnimation = false;\n\n    if (direction > 0) {\n      this._scrollDown(choiceListScrollTop, strength, destination);\n\n      if (choiceListScrollTop < destination) {\n        continueAnimation = true;\n      }\n    } else {\n      this._scrollUp(choiceListScrollTop, strength, destination);\n\n      if (choiceListScrollTop > destination) {\n        continueAnimation = true;\n      }\n    }\n\n    if (continueAnimation) {\n      requestAnimationFrame(() => {\n        this._animateScroll(destination, direction);\n      });\n    }\n  }\n}\n"
  },
  {
    "path": "src/scripts/components/wrapped-element.ts",
    "content": "import { ClassNames } from '../interfaces/class-names';\nimport { EventTypes } from '../interfaces/event-type';\nimport { addClassesToElement, dispatchEvent, removeClassesFromElement } from '../lib/utils';\nimport { EventMap } from '../interfaces';\n\nexport default class WrappedElement<T extends HTMLInputElement | HTMLSelectElement> {\n  element: T;\n\n  classNames: ClassNames;\n\n  isDisabled: boolean;\n\n  constructor({ element, classNames }) {\n    this.element = element;\n    this.classNames = classNames;\n    this.isDisabled = false;\n  }\n\n  get isActive(): boolean {\n    return this.element.dataset.choice === 'active';\n  }\n\n  get dir(): string {\n    return this.element.dir;\n  }\n\n  get value(): string {\n    return this.element.value;\n  }\n\n  set value(value: string) {\n    this.element.setAttribute('value', value);\n    this.element.value = value;\n  }\n\n  conceal(): void {\n    const el = this.element;\n    // Hide passed input\n    addClassesToElement(el, this.classNames.input);\n    el.hidden = true;\n\n    // Remove element from tab index\n    el.tabIndex = -1;\n\n    // Backup original styles if any\n    const origStyle = el.getAttribute('style');\n\n    if (origStyle) {\n      el.setAttribute('data-choice-orig-style', origStyle);\n    }\n\n    el.setAttribute('data-choice', 'active');\n  }\n\n  reveal(): void {\n    const el = this.element;\n    // Reinstate passed element\n    removeClassesFromElement(el, this.classNames.input);\n    el.hidden = false;\n    el.removeAttribute('tabindex');\n\n    // Recover original styles if any\n    const origStyle = el.getAttribute('data-choice-orig-style');\n\n    if (origStyle) {\n      el.removeAttribute('data-choice-orig-style');\n      el.setAttribute('style', origStyle);\n    } else {\n      el.removeAttribute('style');\n    }\n    el.removeAttribute('data-choice');\n  }\n\n  enable(): void {\n    this.element.removeAttribute('disabled');\n    this.element.disabled = false;\n    this.isDisabled = false;\n  }\n\n  disable(): void {\n    this.element.setAttribute('disabled', '');\n    this.element.disabled = true;\n    this.isDisabled = true;\n  }\n\n  triggerEvent<K extends EventTypes>(eventType: EventTypes, data?: EventMap[K]['detail']): void {\n    dispatchEvent(this.element, eventType, data || {});\n  }\n}\n"
  },
  {
    "path": "src/scripts/components/wrapped-input.ts",
    "content": "import WrappedElement from './wrapped-element';\n\nexport default class WrappedInput extends WrappedElement<HTMLInputElement> {}\n"
  },
  {
    "path": "src/scripts/components/wrapped-select.ts",
    "content": "import { parseCustomProperties } from '../lib/utils';\nimport { ClassNames } from '../interfaces/class-names';\nimport WrappedElement from './wrapped-element';\nimport { GroupFull } from '../interfaces/group-full';\nimport { ChoiceFull } from '../interfaces/choice-full';\nimport { stringToHtmlClass } from '../lib/choice-input';\nimport { isHtmlOptgroup, isHtmlOption } from '../lib/html-guard-statements';\n\nexport default class WrappedSelect extends WrappedElement<HTMLSelectElement> {\n  classNames: ClassNames;\n\n  template: (data: object) => HTMLOptionElement;\n\n  extractPlaceholder: boolean;\n\n  constructor({\n    element,\n    classNames,\n    template,\n    extractPlaceholder,\n  }: {\n    element: HTMLSelectElement;\n    classNames: ClassNames;\n    template: (data: object) => HTMLOptionElement;\n    extractPlaceholder: boolean;\n  }) {\n    super({ element, classNames });\n    this.template = template;\n    this.extractPlaceholder = extractPlaceholder;\n  }\n\n  get placeholderOption(): HTMLOptionElement | null {\n    return (\n      this.element.querySelector('option[value=\"\"]') ||\n      // Backward compatibility layer for the non-standard placeholder attribute supported in older versions.\n      this.element.querySelector('option[placeholder]')\n    );\n  }\n\n  addOptions(choices: ChoiceFull[]): void {\n    const fragment = document.createDocumentFragment();\n    choices.forEach((obj) => {\n      const choice = obj;\n      if (choice.element) {\n        return;\n      }\n\n      const option = this.template(choice);\n      fragment.appendChild(option);\n      choice.element = option;\n    });\n    this.element.appendChild(fragment);\n  }\n\n  optionsAsChoices(): (ChoiceFull | GroupFull)[] {\n    const choices: (ChoiceFull | GroupFull)[] = [];\n\n    this.element.querySelectorAll<HTMLElement>(':scope > option, :scope > optgroup').forEach((e) => {\n      if (isHtmlOption(e)) {\n        choices.push(this._optionToChoice(e));\n      } else if (isHtmlOptgroup(e)) {\n        choices.push(this._optgroupToChoice(e));\n      }\n      // todo: hr as empty optgroup, requires displaying empty opt-groups to be useful\n    });\n\n    return choices;\n  }\n\n  // eslint-disable-next-line class-methods-use-this\n  _optionToChoice(option: HTMLOptionElement): ChoiceFull {\n    // option.value returns the label if there is no value attribute, which can break legacy placeholder attribute support\n    if (!option.hasAttribute('value') && option.hasAttribute('placeholder')) {\n      option.setAttribute('value', '');\n      option.value = '';\n    }\n\n    return {\n      id: 0,\n      group: null,\n      score: 0,\n      rank: 0,\n      value: option.value,\n      // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/option\n      // This attribute is text for the label indicating the meaning of the option. If the `label` attribute isn't defined, its value is that of the element text content (ie `innerText`).\n      label: option.label,\n      element: option,\n      active: true,\n      // this returns true if nothing is selected on initial load, which will break placeholder support\n      selected: this.extractPlaceholder ? option.selected : option.hasAttribute('selected'),\n      disabled: option.disabled,\n      highlighted: false,\n      placeholder: this.extractPlaceholder && (!option.value || option.hasAttribute('placeholder')),\n      labelClass:\n        typeof option.dataset.labelClass !== 'undefined' ? stringToHtmlClass(option.dataset.labelClass) : undefined,\n      labelDescription:\n        typeof option.dataset.labelDescription !== 'undefined'\n          ? { trusted: option.dataset.labelDescription }\n          : undefined,\n      customProperties: parseCustomProperties(option.dataset.customProperties),\n    };\n  }\n\n  _optgroupToChoice(optgroup: HTMLOptGroupElement): GroupFull {\n    const options = optgroup.querySelectorAll('option');\n    const choices = Array.from(options).map((option) => this._optionToChoice(option));\n\n    return {\n      id: 0,\n      label: optgroup.label || '',\n      element: optgroup,\n      active: !!choices.length,\n      disabled: optgroup.disabled,\n      choices,\n    };\n  }\n}\n"
  },
  {
    "path": "src/scripts/constants.ts",
    "content": "export const SCROLLING_SPEED: number = 4 as const;\n"
  },
  {
    "path": "src/scripts/defaults.ts",
    "content": "import { ClassNames } from './interfaces/class-names';\nimport { Options } from './interfaces/options';\nimport { sanitise, sortByAlpha } from './lib/utils';\nimport { EventChoice } from './interfaces';\n\nexport const DEFAULT_CLASSNAMES: ClassNames = {\n  containerOuter: ['choices'],\n  containerInner: ['choices__inner'],\n  input: ['choices__input'],\n  inputCloned: ['choices__input--cloned'],\n  list: ['choices__list'],\n  listItems: ['choices__list--multiple'],\n  listSingle: ['choices__list--single'],\n  listDropdown: ['choices__list--dropdown'],\n  item: ['choices__item'],\n  itemSelectable: ['choices__item--selectable'],\n  itemDisabled: ['choices__item--disabled'],\n  itemChoice: ['choices__item--choice'],\n  description: ['choices__description'],\n  placeholder: ['choices__placeholder'],\n  group: ['choices__group'],\n  groupHeading: ['choices__heading'],\n  button: ['choices__button'],\n  activeState: ['is-active'],\n  focusState: ['is-focused'],\n  openState: ['is-open'],\n  disabledState: ['is-disabled'],\n  highlightedState: ['is-highlighted'],\n  selectedState: ['is-selected'],\n  flippedState: ['is-flipped'],\n  loadingState: ['is-loading'],\n  invalidState: ['is-invalid'],\n  notice: ['choices__notice'],\n  addChoice: ['choices__item--selectable', 'add-choice'],\n  noResults: ['has-no-results'],\n  noChoices: ['has-no-choices'],\n} as const;\n\nexport const DEFAULT_CONFIG: Options = {\n  items: [],\n  choices: [],\n  silent: false,\n  renderChoiceLimit: -1,\n  maxItemCount: -1,\n  closeDropdownOnSelect: 'auto',\n  singleModeForMultiSelect: false,\n  addChoices: false,\n  addItems: true,\n  addItemFilter: (value: string): boolean => !!value && value !== '',\n  removeItems: true,\n  removeItemButton: false,\n  removeItemButtonAlignLeft: false,\n  editItems: false,\n  allowHTML: false,\n  allowHtmlUserInput: false,\n  duplicateItemsAllowed: true,\n  delimiter: ',',\n  paste: true,\n  searchEnabled: true,\n  searchChoices: true,\n  searchDisabledChoices: false,\n  searchFloor: 1,\n  searchResultLimit: 4,\n  searchFields: ['label', 'value'],\n  position: 'auto',\n  resetScrollPosition: true,\n  shouldSort: true,\n  shouldSortItems: false,\n  sorter: sortByAlpha,\n  shadowRoot: null,\n  placeholder: true,\n  placeholderValue: null,\n  searchPlaceholderValue: null,\n  prependValue: null,\n  appendValue: null,\n  renderSelectedChoices: 'auto',\n  searchRenderSelectedChoices: true,\n  loadingText: 'Loading...',\n  noResultsText: 'No results found',\n  noChoicesText: 'No choices to choose from',\n  itemSelectText: 'Press to select',\n  uniqueItemText: 'Only unique values can be added',\n  customAddItemText: 'Only values matching specific conditions can be added',\n  addItemText: (value: string) => `Press Enter to add <b>\"${value}\"</b>`,\n  removeItemIconText: (): string => `Remove item`,\n  removeItemLabelText: (value: string, _valueRaw: string, i?: EventChoice): string =>\n    `Remove item: ${i ? sanitise<string>(i.label) : value}`,\n  maxItemText: (maxItemCount: number): string => `Only ${maxItemCount} values can be added`,\n  valueComparer: (value1: string, value2: string): boolean => value1 === value2,\n  fuseOptions: {\n    includeScore: true,\n  },\n  labelId: '',\n  callbackOnInit: null,\n  callbackOnCreateTemplates: null,\n  classNames: DEFAULT_CLASSNAMES,\n  appendGroupInSearch: false,\n} as const;\n"
  },
  {
    "path": "src/scripts/interfaces/action-type.ts",
    "content": "import { Types } from './types';\n\nexport const ActionType = {\n  ADD_CHOICE: 'ADD_CHOICE',\n  REMOVE_CHOICE: 'REMOVE_CHOICE',\n  FILTER_CHOICES: 'FILTER_CHOICES',\n  ACTIVATE_CHOICES: 'ACTIVATE_CHOICES',\n  CLEAR_CHOICES: 'CLEAR_CHOICES',\n  ADD_GROUP: 'ADD_GROUP',\n  ADD_ITEM: 'ADD_ITEM',\n  REMOVE_ITEM: 'REMOVE_ITEM',\n  HIGHLIGHT_ITEM: 'HIGHLIGHT_ITEM',\n} as const;\n\nexport type ActionTypes = Types.ValueOf<typeof ActionType>;\n"
  },
  {
    "path": "src/scripts/interfaces/build-flags.ts",
    "content": "export const canUseDom: boolean =\n  process.env.CHOICES_CAN_USE_DOM !== undefined\n    ? process.env.CHOICES_CAN_USE_DOM === '1'\n    : !!(typeof document !== 'undefined' && document.createElement);\n\nexport const searchFuse: string | undefined = process.env.CHOICES_SEARCH_FUSE;\nexport const searchKMP: boolean = process.env.CHOICES_SEARCH_KMP === '1';\n\n/**\n * These are not directly used, as an exported object (even as const) will prevent tree-shake away code paths\n */\n\nexport const BuildFlags = {\n  searchFuse,\n  searchKMP,\n  canUseDom,\n} as const;\n"
  },
  {
    "path": "src/scripts/interfaces/choice-full.ts",
    "content": "import { StringUntrusted } from './string-untrusted';\nimport { StringPreEscaped } from './string-pre-escaped';\nimport { Types } from './types';\n// eslint-disable-next-line import/no-cycle\nimport { GroupFull } from './group-full';\n\n/*\n  A disabled choice appears in the choice dropdown but cannot be selected\n  A selected choice has been added to the passed input's value (added as an item)\n  An active choice appears within the choice dropdown (ie search sets active to false if it doesn't match)\n*/\nexport interface ChoiceFull {\n  id: number;\n  highlighted: boolean;\n  element?: HTMLOptionElement | HTMLOptGroupElement;\n  itemEl?: HTMLElement;\n  choiceEl?: HTMLElement;\n  labelClass?: Array<string>;\n  labelDescription?: StringPreEscaped | StringUntrusted | string;\n  customProperties?: Types.CustomProperties;\n  disabled: boolean;\n  active: boolean;\n  elementId?: string;\n  group: GroupFull | null;\n  label: StringUntrusted | string;\n  placeholder: boolean;\n  selected: boolean;\n  value: string;\n  score: number;\n  rank: number;\n}\n"
  },
  {
    "path": "src/scripts/interfaces/class-names.ts",
    "content": "/** Classes added to HTML generated by  By default classnames follow the BEM notation. */\nexport interface ClassNames {\n  /** @default ['choices'] */\n  containerOuter: string | Array<string>;\n  /** @default ['choices__inner'] */\n  containerInner: string | Array<string>;\n  /** @default ['choices__input'] */\n  input: string | Array<string>;\n  /** @default ['choices__input--cloned'] */\n  inputCloned: string | Array<string>;\n  /** @default ['choices__list'] */\n  list: string | Array<string>;\n  /** @default ['choices__list--multiple'] */\n  listItems: string | Array<string>;\n  /** @default ['choices__list--single'] */\n  listSingle: string | Array<string>;\n  /** @default ['choices__list--dropdown'] */\n  listDropdown: string | Array<string>;\n  /** @default ['choices__item'] */\n  item: string | Array<string>;\n  /** @default ['choices__item--selectable'] */\n  itemSelectable: string | Array<string>;\n  /** @default ['choices__item--disabled'] */\n  itemDisabled: string | Array<string>;\n  /** @default ['choices__item--choice'] */\n  itemChoice: string | Array<string>;\n  /** @default ['choices__description'] */\n  description: string | Array<string>;\n  /** @default ['choices__placeholder'] */\n  placeholder: string | Array<string>;\n  /** @default ['choices__group'] */\n  group: string | Array<string>;\n  /** @default ['choices__heading'] */\n  groupHeading: string | Array<string>;\n  /** @default ['choices__button'] */\n  button: string | Array<string>;\n  /** @default ['is-active'] */\n  activeState: string | Array<string>;\n  /** @default ['is-focused'] */\n  focusState: string | Array<string>;\n  /** @default ['is-open'] */\n  openState: string | Array<string>;\n  /** @default ['is-disabled'] */\n  disabledState: string | Array<string>;\n  /** @default ['is-highlighted'] */\n  highlightedState: string | Array<string>;\n  /** @default ['is-selected'] */\n  selectedState: string | Array<string>;\n  /** @default ['is-flipped'] */\n  flippedState: string | Array<string>;\n  /** @default ['is-loading'] */\n  loadingState: string | Array<string>;\n  /** @default ['is-invalid'] */\n  invalidState: string | Array<string>;\n  /** @default ['choices__notice'] */\n  notice: string | Array<string>;\n  /** @default ['choices__item--selectable', 'add-choice'] */\n  addChoice: string | Array<string>;\n  /** @default ['has-no-results'] */\n  noResults: string | Array<string>;\n  /** @default ['has-no-choices'] */\n  noChoices: string | Array<string>;\n}\n"
  },
  {
    "path": "src/scripts/interfaces/event-choice.ts",
    "content": "// eslint-disable-next-line import/no-cycle\nimport { InputChoice } from './input-choice';\n\nexport type EventChoiceValueType<B extends boolean> = B extends true ? string : EventChoice;\n\nexport interface EventChoice extends InputChoice {\n  element?: HTMLOptionElement | HTMLOptGroupElement;\n  groupValue?: string;\n  keyCode?: number;\n}\n"
  },
  {
    "path": "src/scripts/interfaces/event-type.ts",
    "content": "import { Types } from './types';\n\nexport const EventType = {\n  showDropdown: 'showDropdown',\n  hideDropdown: 'hideDropdown',\n  change: 'change',\n  choice: 'choice',\n  search: 'search',\n  addItem: 'addItem',\n  removeItem: 'removeItem',\n  highlightItem: 'highlightItem',\n  highlightChoice: 'highlightChoice',\n  unhighlightItem: 'unhighlightItem',\n} as const;\n\nexport type EventTypes = Types.ValueOf<typeof EventType>;\n"
  },
  {
    "path": "src/scripts/interfaces/group-full.ts",
    "content": "// eslint-disable-next-line import/no-cycle\nimport { ChoiceFull } from './choice-full';\n\nexport interface GroupFull {\n  id: number;\n  active: boolean;\n  disabled: boolean;\n  label?: string;\n  element?: HTMLOptGroupElement;\n  groupEl?: HTMLElement;\n  choices: ChoiceFull[];\n}\n"
  },
  {
    "path": "src/scripts/interfaces/index.ts",
    "content": "export * from './action-type';\nexport * from './input-choice';\nexport * from './input-group';\nexport * from './event-choice';\nexport * from './class-names';\nexport * from './event-type';\nexport * from './item';\nexport * from './keycode-map';\nexport * from './options';\nexport * from './passed-element';\nexport * from './passed-element-type';\nexport * from './position-options-type';\nexport * from './state';\nexport * from './types';\n"
  },
  {
    "path": "src/scripts/interfaces/input-choice.ts",
    "content": "import { StringUntrusted } from './string-untrusted';\nimport { StringPreEscaped } from './string-pre-escaped';\n// eslint-disable-next-line\nimport { Types } from './types';\n\nexport interface InputChoice {\n  id?: number;\n  highlighted?: boolean;\n  labelClass?: string | Array<string>;\n  labelDescription?: StringPreEscaped | StringUntrusted | string;\n  customProperties?: Types.CustomProperties;\n  disabled?: boolean;\n  active?: boolean;\n  label: StringUntrusted | string;\n  placeholder?: boolean;\n  selected?: boolean;\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  value: any; // string;\n}\n"
  },
  {
    "path": "src/scripts/interfaces/input-group.ts",
    "content": "import { InputChoice } from './input-choice';\nimport { StringUntrusted } from './string-untrusted';\n\nexport interface InputGroup {\n  id?: number;\n  active?: boolean;\n  disabled?: boolean;\n  label?: StringUntrusted | string;\n  value: string;\n  choices: InputChoice[];\n}\n"
  },
  {
    "path": "src/scripts/interfaces/item.ts",
    "content": "import { InputChoice } from './input-choice';\nimport { InputGroup } from './input-group';\n\n/**\n * @deprecated Use InputChoice instead\n */\nexport interface Item extends InputChoice {}\n\n/**\n * @deprecated Use InputChoice instead\n */\nexport interface Choice extends InputChoice {}\n\n/**\n * @deprecated Use InputGroup instead\n */\nexport interface Group extends InputGroup {}\n"
  },
  {
    "path": "src/scripts/interfaces/keycode-map.ts",
    "content": "export const KeyCodeMap = {\n  TAB_KEY: 9,\n  SHIFT_KEY: 16,\n  BACK_KEY: 46,\n  DELETE_KEY: 8,\n  ENTER_KEY: 13,\n  A_KEY: 65,\n  ESC_KEY: 27,\n  UP_KEY: 38,\n  DOWN_KEY: 40,\n  PAGE_UP_KEY: 33,\n  PAGE_DOWN_KEY: 34,\n} as const;\n"
  },
  {
    "path": "src/scripts/interfaces/options.ts",
    "content": "import { IFuseOptions } from 'fuse.js';\nimport { InputChoice } from './input-choice';\nimport { ClassNames } from './class-names';\nimport { PositionOptionsType } from './position-options-type';\nimport { Types } from './types';\n// eslint-disable-next-line import/no-cycle\nimport { CallbackOnCreateTemplatesFn } from './templates';\n\nexport const ObjectsInConfig: string[] = ['fuseOptions', 'classNames'];\n\n/**\n * Choices options interface\n *\n * **Terminology**\n *\n * - **Choice:** A choice is a value a user can select. A choice would be equivalent to the `<option></option>` element within a select input.\n * - **Group:** A group is a collection of choices. A group should be seen as equivalent to a `<optgroup></optgroup>` element within a select input.\n * - **Item:** An item is an inputted value **_(text input)_** or a selected choice **_(select element)_**. In the context of a select element, an item is equivelent to a selected option element: `<option value=\"Hello\" selected></option>` whereas in the context of a text input an item is equivelant to `<input type=\"text\" value=\"Hello\">`\n */\nexport interface Options {\n  /**\n   * Optionally suppress console errors and warnings.\n   *\n   * **Input types affected:** text, select-single, select-multiple\n   *\n   * @default false\n   */\n  silent: boolean;\n\n  /**\n   * Add pre-selected items (see terminology) to text input.\n   *\n   * **Input types affected:** text\n   *\n   * @example\n   * ```\n   * ['value 1', 'value 2', 'value 3']\n   * ```\n   *\n   * @example\n   * ```\n   * [{\n   *    value: 'Value 1',\n   *    label: 'Label 1',\n   *    id: 1\n   *  },\n   *  {\n   *    value: 'Value 2',\n   *    label: 'Label 2',\n   *    id: 2,\n   *    customProperties: {\n   *      random: 'I am a custom property'\n   *  }\n   * }]\n   * ```\n   *\n   * @default []\n   */\n  items: string[] | InputChoice[];\n\n  /**\n   * Add choices (see terminology) to select input.\n   *\n   * **Input types affected:** select-one, select-multiple\n   *\n   * @example\n   * ```\n   * [{\n   *   value: 'Option 1',\n   *   label: 'Option 1',\n   *   selected: true,\n   *   disabled: false,\n   * },\n   * {\n   *   value: 'Option 2',\n   *   label: 'Option 2',\n   *   selected: false,\n   *   disabled: true,\n   *   customProperties: {\n   *     description: 'Custom description about Option 2',\n   *     random: 'Another random custom property'\n   *   },\n   * },\n   * {\n   *   label: 'Group 1',\n   *   choices: [{\n   *     value: 'Option 3',\n   *     label: 'Option 4',\n   *     selected: true,\n   *     disabled: false,\n   *   },\n   *   {\n   *     value: 'Option 2',\n   *     label: 'Option 2',\n   *     selected: false,\n   *     disabled: true,\n   *     customProperties: {\n   *       description: 'Custom description about Option 2',\n   *       random: 'Another random custom property'\n   *     }\n   *   }]\n   * }]\n   * ```\n   *\n   * @default []\n   */\n  choices: InputChoice[];\n\n  /**\n   * The amount of choices to be rendered within the dropdown list `(\"-1\" indicates no limit)`. This is useful if you have a lot of choices where it is easier for a user to use the search area to find a choice.\n   *\n   * **Input types affected:** select-one, select-multiple\n   *\n   * @default -1\n   */\n  renderChoiceLimit: number;\n\n  /**\n   * The amount of items a user can input/select `(\"-1\" indicates no limit)`.\n   *\n   * **Input types affected:** text, select-multiple\n   *\n   * @default -1\n   */\n  maxItemCount: number;\n\n  /**\n   * Control how the dropdown closes after making a selection for select-one or select-multiple\n   *\n   * 'auto' defaults based on backing-element type:\n   * select-one: true\n   * select-multiple: false\n   *\n   * **Input types affected:** select-one, select-multiple\n   *\n   * @default 'auto'\n   */\n  closeDropdownOnSelect: boolean | 'auto';\n\n  /**\n   * Make select-multiple with a max item count of 1 work similar to select-one does.\n   * Selecting an item will auto-close the dropdown and swap any existing item for the just selected choice.\n   * If applied to a select-one, it functions as above and not the standard select-one.\n   *\n   * **Input types affected:** select-one, select-multiple\n   *\n   * @default false\n   */\n  singleModeForMultiSelect: boolean;\n\n  /**\n   * Whether a user can add choices dynamically.\n   *\n   * **Input types affected:** select-one, select-multiple\n   *\n   * @default false\n   */\n  addChoices: boolean;\n\n  /**\n   * Whether a user can add items.\n   *\n   * **Input types affected:** text\n   *\n   * @default true\n   */\n  addItems: boolean;\n\n  /**\n   * A filter that will need to pass for a user to successfully add an item.\n   *\n   * **Input types affected:** text, select-one, select-multiple\n   *\n   * @default (value) => !!value && value !== ''\n   */\n  addItemFilter: string | RegExp | Types.FilterFunction | null;\n\n  /**\n   * The text that is shown when a user has inputted a new item but has not pressed the enter key. To access the current input value, pass a function with a `value` argument (see the **default config** [https://github.com/jshjohnson/Choices#setup] for an example), otherwise pass a string.\n   * The raw non-sanitised value is passed as a 2nd argument.\n   *\n   * Return type must be safe to insert into HTML (ie use the 1st argument which is sanitised)\n   *\n   * **Input types affected:** text, one-select, select-one, select-multiple\n   *\n   * @default\n   * ```\n   * (value, valueRaw) => `Press Enter to add <b>\"${value}\"</b>`;\n   * ```\n   */\n  addItemText: string | Types.NoticeStringFunction;\n\n  /**\n   * The text/icon for the remove button. To access the item's value, pass a function with a `value` argument (see the **default config** [https://github.com/jshjohnson/Choices#setup] for an example), otherwise pass a string.\n   * The raw non-sanitised value is passed as a 2nd argument.\n   *\n   * Return type must be safe to insert into HTML (ie use the 1st argument which is sanitised)\n   *\n   * **Input types affected:** text, select-one, select-multiple\n   *\n   * @default\n   * ```\n   * (value, valueRaw, item) => `Remove item`;\n   * ```\n   */\n  removeItemIconText: string | Types.NoticeStringFunction;\n\n  /**\n   * The text for the remove button's aria label. To access the item's value, pass a function with a `value` argument (see the **default config** [https://github.com/jshjohnson/Choices#setup] for an example), otherwise pass a string.\n   * The raw non-sanitised value is passed as a 2nd argument.\n   *\n   * Return type must be safe to insert into HTML (ie use the 1st argument which is sanitised)\n   *\n   * **Input types affected:** text, select-one, select-multiple\n   *\n   * @default\n   * ```\n   * (value, valueRaw, item) => `Remove item: ${value}`;\n   * ```\n   */\n  removeItemLabelText: string | Types.NoticeStringFunction;\n\n  /**\n   * Whether a user can remove items.\n   *\n   * **Input types affected:** text, select-multiple\n   *\n   * @default true\n   */\n  removeItems: boolean;\n\n  /**\n   * Whether each item should have a remove button.\n   *\n   * **Input types affected:** text, select-one, select-multiple\n   *\n   * @default false\n   */\n  removeItemButton: boolean;\n  /**\n   * Align item remove button left vs right.\n   *\n   * **Input types affected:** text, select-one, select-multiple\n   *\n   * @default false\n   */\n  removeItemButtonAlignLeft: boolean;\n  /**\n   * Whether a user can edit items. An item's value can be edited by pressing the backspace.\n   *\n   * **Input types affected:** text\n   *\n   * @default false\n   */\n  editItems: boolean;\n\n  /**\n   * Whether HTML should be rendered in all Choices elements.\n   * If `false`, all elements (placeholder, items, etc.) will be treated as plain text.\n   * If `true`, this can be used to perform XSS scripting attacks if you load choices from a remote source.\n   *\n   * **Input types affected:** text, select-one, select-multiple\n   *\n   * @default false\n   */\n  allowHTML: boolean;\n\n  /**\n   * Whether HTML should be escaped on input when `addItems` or `addChoices` is true.\n   * If `false`, user input will be treated as plain text.\n   * If `true`, this can be used to perform XSS scripting attacks if you load previously submitted choices from a remote source.\n   *\n   * **Input types affected:** text, select-one, select-multiple\n   *\n   * @default false\n   */\n  allowHtmlUserInput: boolean;\n\n  /**\n   * Whether each inputted/chosen item should be unique.\n   *\n   * **Input types affected:** text, `select-multiple`, `select-one`\n   *\n   * @default true\n   */\n  duplicateItemsAllowed: boolean;\n\n  /**\n   * What divides each value. The default delimiter separates each value with a comma: `\"Value 1, Value 2, Value 3\"`.\n   *\n   * **Input types affected:** text\n   *\n   * @default ','\n   */\n  delimiter: string;\n\n  /**\n   * Whether a user can paste into the input.\n   *\n   * **Input types affected:** text, select-multiple\n   *\n   * @default true\n   */\n  paste: boolean;\n\n  /**\n   * Whether a search area should be shown.\n   *\n   * **Input types affected:** select-one, select-multiple\n   *\n   * @default true\n   */\n  searchEnabled: boolean;\n\n  /**\n   * Whether choices should be filtered by input or not. If `false`, the search event will still emit, but choices will not be filtered.\n   *\n   * **Input types affected:** select-one\n   *\n   * @default true\n   */\n  searchChoices: boolean;\n\n  /**\n   * Whether disabled choices should be included in search results. If `true`, disabled choices will appear in search results but still cannot be selected.\n   *\n   * **Input types affected:** select-one, select-multiple\n   *\n   * @default false\n   */\n  searchDisabledChoices: boolean;\n\n  /**\n   * The minimum length a search value should be before choices are searched.\n   *\n   * **Input types affected:** select-one, select-multiple\n   *\n   * @default 1\n   */\n  searchFloor: number;\n\n  /**\n   * The maximum amount of search results to show. `(\"-1\" indicates no limit)`\n   *\n   * **Input types affected:** select-one, select-multiple\n   *\n   * @default 4\n   */\n  searchResultLimit: number;\n\n  /**\n   * Specify which fields should be used when a user is searching. If you have added custom properties to your choices, you can add these values thus: `['label', 'value', 'customProperties.example']`.\n   *\n   * Input types affected:select-one, select-multiple\n   *\n   * @default ['label', 'value']\n   */\n  searchFields: string[];\n\n  /**\n   * Whether the dropdown should appear above `(top)` or below `(bottom)` the input. By default, if there is not enough space within the window the dropdown will appear above the input, otherwise below it.\n   *\n   * **Input types affected:** select-one, select-multiple\n   *\n   * @default 'auto'\n   */\n  position: PositionOptionsType;\n\n  /**\n   * Whether the scroll position should reset after adding an item.\n   *\n   * **Input types affected:** select-multiple\n   *\n   * @default true\n   */\n  resetScrollPosition: boolean;\n\n  /**\n   * The shadow root for use within ShadowDom\n   */\n  shadowRoot: ShadowRoot | null;\n\n  /**\n   * Whether choices and groups should be sorted. If false, choices/groups will appear in the order they were given.\n   *\n   * **Input types affected:** select-one, select-multiple\n   *\n   * @default true\n   */\n  shouldSort: boolean;\n\n  /**\n   * Whether items should be sorted. If false, items will appear in the order they were selected.\n   *\n   * **Input types affected:** text, select-multiple\n   *\n   * @default false\n   */\n  shouldSortItems: boolean;\n\n  /**\n   * The function that will sort choices and items before they are displayed (unless a user is searching). By default choices and items are sorted by alphabetical order.\n   *\n   * **Input types affected:** select-one, select-multiple\n   *\n   * @example\n   * ```\n   * // Sorting via length of label from largest to smallest\n   * const example = new Choices(element, {\n   *   sorter: function(a, b) {\n   *     return b.label.length - a.label.length;\n   *   },\n   * };\n   * ```\n   *\n   * @default sortByAlpha\n   */\n  sorter: (current: Types.RecordToCompare, next: Types.RecordToCompare) => number;\n\n  /**\n   * Whether the input should show a placeholder. Used in conjunction with `placeholderValue`. If `placeholder` is set to true and no value is passed to `placeholderValue`, the passed input's placeholder attribute will be used as the placeholder value.\n   *\n   * **Input types affected:** text, select-multiple\n   *\n   * @note For single select boxes, the recommended way of adding a placeholder is as follows:\n   * ```\n   * <select data-placeholder=\"This is a placeholder\">\n   *   <option>...</option>\n   *   <option>...</option>\n   *   <option>...</option>\n   * </select>\n   * ```\n   *\n   * @default true\n   */\n  placeholder: boolean;\n\n  /**\n   * The value of the inputs placeholder.\n   *\n   * **Input types affected:** text, select-multiple\n   *\n   * @default null\n   */\n  placeholderValue: string | null;\n\n  /**\n   * The value of the search inputs placeholder.\n   *\n   * **Input types affected:** select-one\n   *\n   * @default null\n   */\n  searchPlaceholderValue: string | null;\n\n  /**\n   * Prepend a value to each item added/selected.\n   *\n   * **Input types affected:** text, select-one, select-multiple\n   *\n   * @default null\n   */\n  prependValue: string | null;\n\n  /**\n   * Append a value to each item added/selected.\n   *\n   * **Input types affected:** text, select-one, select-multiple\n   *\n   * @default null\n   */\n  appendValue: string | null;\n\n  /**\n   * Whether selected choices should be removed from the list. By default choices are removed when they are selected in multiple select box. To always render choices pass `always`.\n   *\n   * **Input types affected:** select-one, select-multiple\n   *\n   * @default 'auto';\n   */\n  renderSelectedChoices: 'auto' | 'always' | boolean;\n\n  /**\n   * Whether selected choices should be removed from the list during search.\n   *\n   * **Input types affected:** select-multiple\n   *\n   * @default false;\n   */\n  searchRenderSelectedChoices: boolean;\n\n  /**\n   * The text that is shown whilst choices are being populated via AJAX.\n   *\n   * **Input types affected:** select-one, select-multiple\n   *\n   * @default 'Loading...'\n   */\n  loadingText: string;\n\n  /**\n   * The text that is shown when a user's search has returned no results. Optionally pass a function returning a string.\n   *\n   * **Input types affected:** select-one, select-multiple\n   *\n   * @default 'No results found'\n   */\n  noResultsText: string | Types.StringFunction;\n\n  /**\n   * The text that is shown when a user has selected all possible choices, or no choices exist. Optionally pass a function returning a string.\n   *\n   * **Input types affected:** select-multiple, select-one\n   *\n   * @default 'No choices to choose from'\n   */\n  noChoicesText: string | Types.StringFunction;\n\n  /**\n   * The text that is shown when a user hovers over a selectable choice. Set to empty to not reserve space for this text.\n   *\n   * **Input types affected:** select-multiple, select-one\n   *\n   * @default 'Press to select'\n   */\n  itemSelectText: string;\n\n  /**\n   * The text that is shown when a user has focus on the input but has already reached the **max item count** [https://github.com/jshjohnson/Choices#maxitemcount]. To access the max item count, pass a function with a `maxItemCount` argument (see the **default config** [https://github.com/jshjohnson/Choices#setup] for an example), otherwise pass a string.\n   *\n   * **Input types affected:** text\n   *\n   * @default\n   * ```\n   * (maxItemCount) => `Only ${maxItemCount} values can be added.`;\n   * ```\n   */\n  maxItemText: string | Types.NoticeLimitFunction;\n\n  /**\n   * If no duplicates are allowed, and the value already exists in the array.\n   *\n   * Return type must be safe to insert into HTML (ie use the 1st argument which is sanitised)\n   *\n   * @default 'Only unique values can be added'\n   */\n  uniqueItemText: string | Types.NoticeStringFunction;\n\n  /**\n   * The text that is shown when addItemFilter is passed and it returns false\n   *\n   * Return type must be safe to insert into HTML (ie use the 1st argument which is sanitised)\n   *\n   * **Input types affected:** text\n   *\n   * @default 'Only values matching specific conditions can be added'\n   */\n  customAddItemText: string | Types.NoticeStringFunction;\n\n  /**\n   * Compare choice and value in appropriate way (e.g. deep equality for objects). To compare choice and value, pass a function with a `valueComparer` argument (see the [default config](https://github.com/jshjohnson/Choices#setup) for an example).\n   *\n   * **Input types affected:** select-one, select-multiple\n   *\n   * @default\n   * ```\n   * (choice, item) => choice === item;\n   * ```\n   */\n  valueComparer: Types.ValueCompareFunction;\n\n  /**\n   * Classes added to HTML generated by  By default classnames follow the BEM notation.\n   *\n   * **Input types affected:** text, select-one, select-multiple\n   */\n  classNames: ClassNames;\n\n  /**\n   * Choices uses the great Fuse library for searching. You can find more options here: https://fusejs.io/api/options.html\n   */\n  fuseOptions: IFuseOptions<unknown>; // IFuseOptions<Choices>;\n\n  /**\n   * ID of the connected label to improve a11y. If set, aria-labelledby will be added.\n   */\n  labelId: string;\n\n  /**\n   * Function to run once Choices initialises.\n   *\n   * **Input types affected:** text, select-one, select-multiple\n   *\n   * @note For each callback, this refers to the current instance of  This can be useful if you need access to methods `(this.disable())` or the config object `(this.config)`.\n   *\n   * @default null\n   */\n  callbackOnInit: (() => void) | null;\n\n  /**\n   * Function to run on template creation. Through this callback it is possible to provide custom templates for the various components of Choices (see terminology). For Choices to work with custom templates, it is important you maintain the various data attributes defined here [https://github.com/jshjohnson/Choices/blob/67f29c286aa21d88847adfcd6304dc7d068dc01f/assets/scripts/src/choices.js#L1993-L2067].\n   *\n   * **Input types affected:** text, select-one, select-multiple\n   *\n   * @note For each callback, `this` refers to the current instance of Choices. This can be useful if you need access to methods `(this.disable())`.\n   *\n   * @example\n   * ```\n   * const example = new Choices(element, {\n   *   callbackOnCreateTemplates: function (template, originalTemplates, getClassNames) {\n   *     var classNames = this.config.classNames;\n   *     return {\n   *       item: (data) => {\n   *         return template(`\n   *           <div class=\"${getClassNames(classNames.item).join(' ')} ${data.highlighted ? classNames.highlightedState : classNames.itemSelectable}\" data-item data-id=\"${data.id}\" data-value=\"${data.value}\" ${data.active ? 'aria-selected=\"true\"' : ''} ${data.disabled ? 'aria-disabled=\"true\"' : ''}>\n   *             <span>&bigstar;</span> ${data.label}\n   *           </div>\n   *         `);\n   *       },\n   *       choice: (data) => {\n   *         return template(`\n   *           <div class=\"${getClassNames(classNames.item).join(' ')} ${classNames.itemChoice} ${data.disabled ? classNames.itemDisabled : classNames.itemSelectable}\" data-select-text=\"${this.config.itemSelectText}\" data-choice ${data.disabled ? 'data-choice-disabled aria-disabled=\"true\"' : 'data-choice-selectable'} data-id=\"${data.id}\" data-value=\"${data.value}\" ${data.groupId ? 'role=\"treeitem\"' : 'role=\"option\"'}>\n   *             <span>&bigstar;</span> ${data.label}\n   *           </div>\n   *         `);\n   *       },\n   *     };\n   *   }\n   * });\n   * ```\n   *\n   * @default null\n   */\n  callbackOnCreateTemplates: CallbackOnCreateTemplatesFn | null;\n\n  appendGroupInSearch: boolean;\n}\n"
  },
  {
    "path": "src/scripts/interfaces/passed-element-type.ts",
    "content": "import { Types } from './types';\n\nexport const PassedElementTypes = {\n  Text: 'text',\n  SelectOne: 'select-one',\n  SelectMultiple: 'select-multiple',\n} as const;\n\nexport type PassedElementType = Types.ValueOf<typeof PassedElementTypes>;\n"
  },
  {
    "path": "src/scripts/interfaces/passed-element.ts",
    "content": "import { InputChoice } from './input-choice';\nimport { EventChoice } from './event-choice';\n\n/**\n * Events fired by Choices behave the same as standard events. Each event is triggered on the element passed to Choices (accessible via `this.passedElement`. Arguments are accessible within the `event.detail` object.\n */\nexport interface EventMap {\n  /**\n   * Triggered each time an item is added (programmatically or by the user).\n   *\n   * **Input types affected:** text, select-one, select-multiple\n   *\n   * Arguments: id, value, label, groupValue\n   */\n  addItem: CustomEvent<EventChoice>;\n\n  /**\n   * Triggered each time an item is removed (programmatically or by the user).\n   *\n   * **Input types affected:** text, select-one, select-multiple\n   *\n   * Arguments: id, value, label, groupValue\n   */\n  removeItem: CustomEvent<EventChoice | undefined>;\n\n  /**\n   * Triggered each time an item is highlighted.\n   *\n   * **Input types affected:** text, select-multiple\n   *\n   * Arguments: id, value, label, groupValue\n   */\n  highlightItem: CustomEvent<EventChoice | undefined>;\n\n  /**\n   * Triggered each time an item is unhighlighted.\n   *\n   * **Input types affected:** text, select-multiple\n   *\n   * Arguments: id, value, label, groupValue\n   */\n  unhighlightItem: CustomEvent<EventChoice | undefined>;\n\n  /**\n   * Triggered each time a choice is selected **by a user**, regardless if it changes the value of the input.\n   *\n   * **Input types affected:** select-one, select-multiple\n   *\n   * Arguments: choice: Choice\n   */\n  choice: CustomEvent<{ choice: InputChoice }>;\n\n  /**\n   * Triggered each time an item is added/removed **by a user**.\n   *\n   * **Input types affected:** text, select-one, select-multiple\n   *\n   * Arguments: value\n   */\n  change: CustomEvent<{ value: string }>;\n\n  /**\n   * Triggered when a user types into an input to search choices. When a search is ended, a search event with an empty value with no resultCount is triggered.\n   *\n   * **Input types affected:** select-one, select-multiple\n   *\n   * Arguments: value, resultCount\n   */\n  search: CustomEvent<{ value: string; resultCount: number }>;\n\n  /**\n   * Triggered when the dropdown is shown.\n   *\n   * **Input types affected:** select-one, select-multiple\n   *\n   * Arguments: -\n   */\n  showDropdown: CustomEvent<undefined>;\n\n  /**\n   * Triggered when the dropdown is hidden.\n   *\n   * **Input types affected:** select-one, select-multiple\n   *\n   * Arguments: -\n   */\n  hideDropdown: CustomEvent<undefined>;\n\n  /**\n   * Triggered when a choice from the dropdown is highlighted.\n   *\n   * Input types affected: select-one, select-multiple\n   * Arguments: el is the choice.passedElement that was affected.\n   */\n  highlightChoice: CustomEvent<{ el: HTMLElement }>;\n}\n"
  },
  {
    "path": "src/scripts/interfaces/position-options-type.ts",
    "content": "export type PositionOptionsType = 'auto' | 'top' | 'bottom';\n"
  },
  {
    "path": "src/scripts/interfaces/search.ts",
    "content": "export interface SearchResult<T extends object> {\n  item: T;\n  score: number;\n  rank: number; // values of 0 means this item is not in the search-result set, and should be discarded\n}\n\nexport interface Searcher<T extends object> {\n  reset(): void;\n  isEmptyIndex(): boolean;\n  index(data: T[]): void;\n  search(needle: string): SearchResult<T>[];\n}\n"
  },
  {
    "path": "src/scripts/interfaces/state.ts",
    "content": "import { ChoiceFull } from './choice-full';\nimport { GroupFull } from './group-full';\n\nexport interface State {\n  choices: ChoiceFull[];\n  groups: GroupFull[];\n  items: ChoiceFull[];\n}\n\nexport type StateChangeSet = {\n  [K in keyof State]: boolean;\n};\n"
  },
  {
    "path": "src/scripts/interfaces/store.ts",
    "content": "import { StateChangeSet, State } from './state';\nimport { ChoiceFull } from './choice-full';\nimport { GroupFull } from './group-full';\nimport { ActionTypes } from './action-type';\n\nexport interface AnyAction<A extends ActionTypes = ActionTypes> {\n  type: A;\n}\n\nexport interface StateUpdate<T> {\n  update: boolean;\n  state: T;\n}\n\nexport type Reducer<T> = (state: T, action: AnyAction, context?: unknown) => StateUpdate<T>;\n\nexport type StoreListener = (changes: StateChangeSet) => void;\n\nexport interface Store {\n  dispatch(action: AnyAction): void;\n\n  subscribe(onChange: StoreListener): void;\n\n  withTxn(func: () => void): void;\n\n  reset(): void;\n\n  get defaultState(): State;\n\n  /**\n   * Get store object\n   */\n  get state(): State;\n\n  /**\n   * Get items from store\n   */\n  get items(): ChoiceFull[];\n\n  /**\n   * Get highlighted items from store\n   */\n  get highlightedActiveItems(): ChoiceFull[];\n\n  /**\n   * Get choices from store\n   */\n  get choices(): ChoiceFull[];\n\n  /**\n   * Get active choices from store\n   */\n  get activeChoices(): ChoiceFull[];\n\n  /**\n   * Get choices that can be searched (excluding placeholders,\n   * optionally excluding disabled based on config)\n   */\n  get searchableChoices(): ChoiceFull[];\n\n  /**\n   * Get groups from store\n   */\n  get groups(): GroupFull[];\n\n  /**\n   * Get active groups from store\n   */\n  get activeGroups(): GroupFull[];\n\n  /**\n   * Get loading state from store\n   */\n  inTxn(): boolean;\n\n  /**\n   * Get single choice by it's ID\n   */\n  getChoiceById(id: number): ChoiceFull | undefined;\n\n  /**\n   * Get group by group id\n   */\n  getGroupById(id: number): GroupFull | undefined;\n}\n"
  },
  {
    "path": "src/scripts/interfaces/string-pre-escaped.ts",
    "content": "export interface StringPreEscaped {\n  readonly trusted: string;\n}\n"
  },
  {
    "path": "src/scripts/interfaces/string-untrusted.ts",
    "content": "export interface StringUntrusted {\n  readonly escaped: string;\n\n  readonly raw: string;\n}\n"
  },
  {
    "path": "src/scripts/interfaces/templates.ts",
    "content": "import { PassedElementType } from './passed-element-type';\nimport { StringPreEscaped } from './string-pre-escaped';\nimport { ChoiceFull } from './choice-full';\nimport { GroupFull } from './group-full';\n// eslint-disable-next-line import/no-cycle\nimport { Options } from './options';\nimport { Types } from './types';\n\nexport type TemplateOptions = Pick<\n  Options,\n  | 'classNames'\n  | 'allowHTML'\n  | 'removeItemButtonAlignLeft'\n  | 'removeItemIconText'\n  | 'removeItemLabelText'\n  | 'searchEnabled'\n  | 'labelId'\n>;\n\nexport const NoticeTypes = {\n  noChoices: 'no-choices',\n  noResults: 'no-results',\n  addChoice: 'add-choice',\n  generic: '',\n} as const;\nexport type NoticeType = Types.ValueOf<typeof NoticeTypes>;\n\nexport type CallbackOnCreateTemplatesFn = (\n  template: Types.StrToEl,\n  escapeForTemplate: Types.EscapeForTemplateFn,\n  getClassNames: Types.GetClassNamesFn,\n) => Partial<Templates>;\n\nexport interface Templates {\n  containerOuter(\n    options: TemplateOptions,\n    dir: HTMLElement['dir'],\n    isSelectElement: boolean,\n    isSelectOneElement: boolean,\n    searchEnabled: boolean,\n    passedElementType: PassedElementType,\n    labelId: string,\n  ): HTMLDivElement;\n\n  containerInner({ classNames: { containerInner } }: TemplateOptions): HTMLDivElement;\n\n  itemList(options: TemplateOptions, isSelectOneElement: boolean): HTMLDivElement;\n\n  placeholder(options: TemplateOptions, value: StringPreEscaped | string): HTMLDivElement;\n\n  item(options: TemplateOptions, choice: ChoiceFull, removeItemButton: boolean): HTMLDivElement;\n\n  choiceList(options: TemplateOptions, isSelectOneElement: boolean): HTMLDivElement;\n\n  choiceGroup(options: TemplateOptions, group: GroupFull): HTMLDivElement;\n\n  choice(options: TemplateOptions, choice: ChoiceFull, selectText: string, groupText?: string): HTMLDivElement;\n\n  input(options: TemplateOptions, placeholderValue: string | null): HTMLInputElement;\n\n  dropdown(options: TemplateOptions): HTMLDivElement;\n\n  notice(options: TemplateOptions, innerText: string, type: NoticeType): HTMLDivElement;\n\n  option(choice: ChoiceFull): HTMLOptionElement;\n}\n"
  },
  {
    "path": "src/scripts/interfaces/types.ts",
    "content": "import { StringUntrusted } from './string-untrusted';\nimport { StringPreEscaped } from './string-pre-escaped';\n// eslint-disable-next-line import/no-cycle\nimport { EventChoice } from './event-choice';\n\nexport namespace Types {\n  export type StrToEl = (str: string) => HTMLElement | HTMLInputElement | HTMLOptionElement;\n  export type EscapeForTemplateFn = (allowHTML: boolean, s: StringUntrusted | StringPreEscaped | string) => string;\n  export type GetClassNamesFn = (s: string | Array<string>) => string;\n  export type StringFunction = () => string;\n  export type NoticeStringFunction = (value: string, valueRaw: string, item?: EventChoice) => string;\n  export type NoticeLimitFunction = (maxItemCount: number) => string;\n  export type FilterFunction = (value: string) => boolean;\n  export type ValueCompareFunction = (value1: string, value2: string) => boolean;\n\n  export interface RecordToCompare {\n    value?: StringUntrusted | string;\n    label?: StringUntrusted | string;\n  }\n  export type ValueOf<T extends object> = T[keyof T];\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  export type CustomProperties = Record<string, any> | string;\n}\n"
  },
  {
    "path": "src/scripts/lib/choice-input.ts",
    "content": "import { InputChoice } from '../interfaces/input-choice';\nimport { InputGroup } from '../interfaces/input-group';\nimport { GroupFull } from '../interfaces/group-full';\nimport { ChoiceFull } from '../interfaces/choice-full';\nimport { sanitise, unwrapStringForRaw } from './utils';\n\ntype MappedInputTypeToChoiceType<T extends string | InputChoice | InputGroup> = T extends InputGroup\n  ? GroupFull\n  : ChoiceFull;\n\nexport const coerceBool = (arg: unknown, defaultValue: boolean = true): boolean =>\n  typeof arg === 'undefined' ? defaultValue : !!arg;\n\nexport const stringToHtmlClass = (input: string | string[] | undefined): string[] | undefined => {\n  if (typeof input === 'string') {\n    // eslint-disable-next-line no-param-reassign\n    input = input.split(' ').filter((s) => s.length);\n  }\n\n  if (Array.isArray(input) && input.length) {\n    return input;\n  }\n\n  return undefined;\n};\n\nexport const mapInputToChoice = <T extends string | InputChoice | InputGroup>(\n  value: T,\n  allowGroup: boolean,\n  allowRawString: boolean = true,\n): MappedInputTypeToChoiceType<T> => {\n  if (typeof value === 'string') {\n    const sanitisedValue = sanitise(value);\n    const userValue = allowRawString || sanitisedValue === value ? value : { escaped: sanitisedValue, raw: value };\n\n    const result: ChoiceFull = mapInputToChoice<InputChoice>(\n      {\n        value,\n        label: userValue,\n        selected: true,\n      },\n      false,\n    );\n\n    return result as MappedInputTypeToChoiceType<T>;\n  }\n\n  const groupOrChoice = value as InputChoice | InputGroup;\n  if ('choices' in groupOrChoice) {\n    if (!allowGroup) {\n      // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/optgroup\n      throw new TypeError(`optGroup is not allowed`);\n    }\n    const group = groupOrChoice;\n    const choices = group.choices.map((e) => mapInputToChoice<InputChoice>(e, false));\n\n    const result: GroupFull = {\n      id: 0, // actual ID will be assigned during _addGroup\n      label: unwrapStringForRaw(group.label) || group.value,\n      active: !!choices.length,\n      disabled: !!group.disabled,\n      choices,\n    };\n\n    return result as MappedInputTypeToChoiceType<T>;\n  }\n\n  const choice = groupOrChoice;\n\n  const result: ChoiceFull = {\n    id: 0, // actual ID will be assigned during _addChoice\n    group: null, // actual group will be assigned during _addGroup but before _addChoice\n    score: 0, // used in search\n    rank: 0, // used in search, stable sort order\n    value: choice.value,\n    label: choice.label || choice.value,\n    active: coerceBool(choice.active),\n    selected: coerceBool(choice.selected, false),\n    disabled: coerceBool(choice.disabled, false),\n    placeholder: coerceBool(choice.placeholder, false),\n    highlighted: false,\n    labelClass: stringToHtmlClass(choice.labelClass),\n    labelDescription: choice.labelDescription,\n    customProperties: choice.customProperties,\n  };\n\n  return result as MappedInputTypeToChoiceType<T>;\n};\n"
  },
  {
    "path": "src/scripts/lib/html-guard-statements.ts",
    "content": "export const isHtmlInputElement = (e: Element): e is HTMLInputElement => e.tagName === 'INPUT';\n\nexport const isHtmlSelectElement = (e: Element): e is HTMLSelectElement => e.tagName === 'SELECT';\n\nexport const isHtmlOption = (e: Element): e is HTMLOptionElement => e.tagName === 'OPTION';\n\nexport const isHtmlOptgroup = (e: Element): e is HTMLOptGroupElement => e.tagName === 'OPTGROUP';\n"
  },
  {
    "path": "src/scripts/lib/utils.ts",
    "content": "import { EventTypes } from '../interfaces/event-type';\nimport { StringUntrusted } from '../interfaces/string-untrusted';\nimport { StringPreEscaped } from '../interfaces/string-pre-escaped';\nimport { ChoiceFull } from '../interfaces/choice-full';\nimport { Types } from '../interfaces/types';\nimport { canUseDom } from '../interfaces/build-flags';\nimport { EventChoice } from '../interfaces';\n\nconst getRandomNumber = (min: number, max: number): number => Math.floor(Math.random() * (max - min) + min);\n\nconst generateChars = (length: number): string =>\n  Array.from({ length }, () => getRandomNumber(0, 36).toString(36)).join('');\n\nexport const generateId = (element: HTMLInputElement | HTMLSelectElement, prefix: string): string => {\n  let id = element.id || (element.name && `${element.name}-${generateChars(2)}`) || generateChars(4);\n  id = id.replace(/(:|\\.|\\[|\\]|,)/g, '');\n  id = `${prefix}-${id}`;\n\n  return id;\n};\n\nexport const getAdjacentEl = (startEl: HTMLElement, selector: string, direction = 1): HTMLElement | null => {\n  const prop = `${direction > 0 ? 'next' : 'previous'}ElementSibling`;\n\n  let sibling = startEl[prop];\n  while (sibling) {\n    if (sibling.matches(selector)) {\n      return sibling;\n    }\n    sibling = sibling[prop];\n  }\n\n  return null;\n};\n\nexport const isScrolledIntoView = (element: HTMLElement, parent: HTMLElement, direction = 1): boolean => {\n  let isVisible: boolean;\n\n  if (direction > 0) {\n    // In view from bottom\n    isVisible = parent.scrollTop + parent.offsetHeight >= element.offsetTop + element.offsetHeight;\n  } else {\n    // In view from top\n    isVisible = element.offsetTop >= parent.scrollTop;\n  }\n\n  return isVisible;\n};\n\nexport const sanitise = <T>(value: T | StringUntrusted | StringPreEscaped | string): T | string => {\n  if (typeof value !== 'string') {\n    if (value === null || value === undefined) {\n      return '';\n    }\n\n    if (typeof value === 'object') {\n      if ('raw' in value) {\n        return sanitise(value.raw);\n      }\n      if ('trusted' in value) {\n        return value.trusted;\n      }\n    }\n\n    return value;\n  }\n\n  return value\n    .replace(/&/g, '&amp;')\n    .replace(/>/g, '&gt;')\n    .replace(/</g, '&lt;')\n    .replace(/'/g, '&#039;')\n    .replace(/\"/g, '&quot;');\n};\n\nexport const strToEl = ((): ((str: string) => Element) => {\n  if (!canUseDom) {\n    // @ts-expect-error Do not run strToEl in non-browser environment\n    return (): void => {};\n  }\n  const tmpEl = document.createElement('div');\n\n  return (str): Element => {\n    tmpEl.innerHTML = str.trim();\n    const firstChild = tmpEl.children[0];\n\n    while (tmpEl.firstChild) {\n      tmpEl.removeChild(tmpEl.firstChild);\n    }\n\n    return firstChild;\n  };\n})();\n\nexport const resolveStringFunction = (fn: Types.StringFunction | string): string => {\n  return typeof fn === 'function' ? fn() : fn;\n};\n\nexport const unwrapStringForRaw = (s?: StringUntrusted | StringPreEscaped | string): string => {\n  if (typeof s === 'string') {\n    return s;\n  }\n\n  if (typeof s === 'object') {\n    if ('trusted' in s) {\n      return s.trusted;\n    }\n    if ('raw' in s) {\n      return s.raw;\n    }\n  }\n\n  return '';\n};\n\nexport const unwrapStringForEscaped = (s?: StringUntrusted | StringPreEscaped | string): string => {\n  if (typeof s === 'string') {\n    return s;\n  }\n\n  if (typeof s === 'object') {\n    if ('escaped' in s) {\n      return s.escaped;\n    }\n    if ('trusted' in s) {\n      return s.trusted;\n    }\n  }\n\n  return '';\n};\n\nexport const getChoiceForOutput = (choice: ChoiceFull, keyCode?: number): EventChoice => {\n  return {\n    id: choice.id,\n    highlighted: choice.highlighted,\n    labelClass: choice.labelClass,\n    labelDescription: unwrapStringForRaw(choice.labelDescription),\n    customProperties: choice.customProperties,\n    disabled: choice.disabled,\n    active: choice.active,\n    label: choice.label,\n    placeholder: choice.placeholder,\n    value: choice.value,\n    groupValue: choice.group ? choice.group.label : undefined,\n    element: choice.element,\n    keyCode,\n  };\n};\n\nexport const resolveNoticeFunction = (\n  fn: Types.NoticeStringFunction | string,\n  value: StringUntrusted | StringPreEscaped | string,\n  item?: EventChoice,\n): string => {\n  return typeof fn === 'function' ? fn(sanitise<string>(value), unwrapStringForRaw(value), item) : fn;\n};\n\nexport const escapeForTemplate = (allowHTML: boolean, s: StringUntrusted | StringPreEscaped | string): string =>\n  allowHTML ? unwrapStringForEscaped(s) : (sanitise(s) as string);\n\nexport const setElementHtml = (\n  el: HTMLElement,\n  allowHtml: boolean,\n  html: StringUntrusted | StringPreEscaped | string,\n): void => {\n  el.innerHTML = escapeForTemplate(allowHtml, html);\n};\n\nexport const sortByAlpha = (\n  { value, label = value }: Types.RecordToCompare,\n  { value: value2, label: label2 = value2 }: Types.RecordToCompare,\n): number =>\n  unwrapStringForRaw(label).localeCompare(unwrapStringForRaw(label2), [], {\n    sensitivity: 'base',\n    ignorePunctuation: true,\n    numeric: true,\n  });\n\nexport const sortByScore = (a: Pick<ChoiceFull, 'score'>, b: Pick<ChoiceFull, 'score'>): number => {\n  return a.score - b.score;\n};\n\nexport const sortByRank = (a: Pick<ChoiceFull, 'rank'>, b: Pick<ChoiceFull, 'rank'>): number => {\n  return a.rank - b.rank;\n};\n\nexport const dispatchEvent = (element: HTMLElement, type: EventTypes, customArgs: object | null = null): boolean => {\n  const event = new CustomEvent(type, {\n    detail: customArgs,\n    bubbles: true,\n    cancelable: true,\n  });\n\n  return element.dispatchEvent(event);\n};\n\nexport const cloneObject = <T>(obj: T): T => (obj !== undefined ? JSON.parse(JSON.stringify(obj)) : undefined);\n\n/**\n * Returns an array of keys present on the first but missing on the second object\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport const diff = (a: Record<string, any>, b: Record<string, any>): string[] => {\n  const aKeys = Object.keys(a).sort();\n  const bKeys = Object.keys(b).sort();\n\n  return aKeys.filter((i) => bKeys.indexOf(i) < 0);\n};\n\nexport const getClassNames = (ClassNames: Array<string> | string): Array<string> => {\n  return Array.isArray(ClassNames) ? ClassNames : [ClassNames];\n};\n\nexport const getClassNamesSelector = (option: string | Array<string> | null): string => {\n  if (option && Array.isArray(option)) {\n    return option\n      .map((item) => {\n        return `.${item}`;\n      })\n      .join('');\n  }\n\n  return `.${option}`;\n};\n\nexport const addClassesToElement = (element: HTMLElement, className: Array<string> | string): void => {\n  element.classList.add(...getClassNames(className));\n};\n\nexport const removeClassesFromElement = (element: HTMLElement, className: Array<string> | string): void => {\n  element.classList.remove(...getClassNames(className));\n};\n\nexport const parseCustomProperties = (customProperties?: string): object | string => {\n  if (typeof customProperties !== 'undefined') {\n    try {\n      return JSON.parse(customProperties);\n    } catch (e) {\n      return customProperties;\n    }\n  }\n\n  return {};\n};\n\nexport const updateClassList = (item: ChoiceFull, add: string | string[], remove: string | string[]): void => {\n  const { itemEl } = item;\n  if (itemEl) {\n    removeClassesFromElement(itemEl, remove);\n    addClassesToElement(itemEl, add);\n  }\n};\n"
  },
  {
    "path": "src/scripts/reducers/choices.ts",
    "content": "/* eslint-disable */\nimport { ActionType, Options, State } from '../interfaces';\nimport { StateUpdate } from '../interfaces/store';\nimport { ChoiceActions } from '../actions/choices';\nimport { ItemActions } from '../actions/items';\nimport { SearchResult } from '../interfaces/search';\nimport { ChoiceFull } from '../interfaces/choice-full';\n\ntype ActionTypes = ChoiceActions | ItemActions;\ntype StateType = State['choices'];\n\nexport default function choices(s: StateType, action: ActionTypes, context?: Options): StateUpdate<StateType> {\n  let state = s;\n  let update = true;\n\n  switch (action.type) {\n    case ActionType.ADD_CHOICE: {\n      state.push(action.choice);\n      break;\n    }\n\n    case ActionType.REMOVE_CHOICE: {\n      action.choice.choiceEl = undefined;\n\n      if (action.choice.group) {\n        action.choice.group.choices = action.choice.group.choices.filter((obj) => obj.id !== action.choice.id);\n      }\n      state = state.filter((obj) => obj.id !== action.choice.id);\n      break;\n    }\n\n    case ActionType.ADD_ITEM:\n    case ActionType.REMOVE_ITEM: {\n      action.item.choiceEl = undefined;\n      break;\n    }\n\n    case ActionType.FILTER_CHOICES: {\n      // avoid O(n^2) algorithm complexity when searching/filtering choices\n      const scoreLookup: SearchResult<ChoiceFull>[] = [];\n      action.results.forEach((result) => {\n        scoreLookup[result.item.id] = result;\n      });\n\n      state.forEach((choice) => {\n        const result = scoreLookup[choice.id];\n        if (result !== undefined) {\n          choice.score = result.score;\n          choice.rank = result.rank;\n          choice.active = true;\n        } else {\n          choice.score = 0;\n          choice.rank = 0;\n          choice.active = false;\n        }\n        if (context && context.appendGroupInSearch) {\n          choice.choiceEl = undefined;\n        }\n      });\n\n      break;\n    }\n\n    case ActionType.ACTIVATE_CHOICES: {\n      state.forEach((choice) => {\n        choice.active = action.active;\n        if (context && context.appendGroupInSearch) {\n          choice.choiceEl = undefined;\n        }\n      });\n      break;\n    }\n\n    case ActionType.CLEAR_CHOICES: {\n      state = [];\n      break;\n    }\n\n    default: {\n      update = false;\n      break;\n    }\n  }\n\n  return { state, update };\n}\n"
  },
  {
    "path": "src/scripts/reducers/groups.ts",
    "content": "import { GroupActions } from '../actions/groups';\nimport { State } from '../interfaces/state';\nimport { ActionType } from '../interfaces';\nimport { StateUpdate } from '../interfaces/store';\nimport { ChoiceActions } from '../actions/choices';\n\ntype ActionTypes = ChoiceActions | GroupActions;\ntype StateType = State['groups'];\n\nexport default function groups(s: StateType, action: ActionTypes): StateUpdate<StateType> {\n  let state = s;\n  let update = true;\n\n  switch (action.type) {\n    case ActionType.ADD_GROUP: {\n      state.push(action.group);\n      break;\n    }\n\n    case ActionType.CLEAR_CHOICES: {\n      state = [];\n      break;\n    }\n\n    default: {\n      update = false;\n      break;\n    }\n  }\n\n  return { state, update };\n}\n"
  },
  {
    "path": "src/scripts/reducers/items.ts",
    "content": "import { ItemActions } from '../actions/items';\nimport { State } from '../interfaces/state';\nimport { ChoiceActions } from '../actions/choices';\nimport { ActionType, Options, PassedElementTypes } from '../interfaces';\nimport { StateUpdate } from '../interfaces/store';\nimport { isHtmlSelectElement } from '../lib/html-guard-statements';\nimport { ChoiceFull } from '../interfaces/choice-full';\nimport { updateClassList } from '../lib/utils';\n\ntype ActionTypes = ChoiceActions | ItemActions;\ntype StateType = State['items'];\n\nconst removeItem = (item: ChoiceFull): void => {\n  const { itemEl } = item;\n  if (itemEl) {\n    itemEl.remove();\n    item.itemEl = undefined;\n  }\n};\n\nexport default function items(s: StateType, action: ActionTypes, context?: Options): StateUpdate<StateType> {\n  let state = s;\n  let update = true;\n\n  switch (action.type) {\n    case ActionType.ADD_ITEM: {\n      action.item.selected = true;\n      const el = action.item.element as HTMLOptionElement | undefined;\n      if (el) {\n        el.selected = true;\n        el.setAttribute('selected', '');\n      }\n\n      state.push(action.item);\n      break;\n    }\n\n    case ActionType.REMOVE_ITEM: {\n      action.item.selected = false;\n      const el = action.item.element as HTMLOptionElement | undefined;\n      if (el) {\n        el.selected = false;\n        el.removeAttribute('selected');\n        // For a select-one, if all options are deselected, the first item is selected. To set a black value, select.value needs to be set\n        const select = el.parentElement;\n        if (select && isHtmlSelectElement(select) && select.type === PassedElementTypes.SelectOne) {\n          select.value = '';\n        }\n      }\n      // this is mixing concerns, but this is *so much faster*\n      removeItem(action.item);\n      state = state.filter((choice) => choice.id !== action.item.id);\n      break;\n    }\n\n    case ActionType.REMOVE_CHOICE: {\n      removeItem(action.choice);\n      state = state.filter((item) => item.id !== action.choice.id);\n      break;\n    }\n\n    case ActionType.HIGHLIGHT_ITEM: {\n      const { highlighted } = action;\n      const item = state.find((obj) => obj.id === action.item.id);\n      if (item && item.highlighted !== highlighted) {\n        item.highlighted = highlighted;\n        if (context) {\n          updateClassList(\n            item,\n            highlighted ? context.classNames.highlightedState : context.classNames.selectedState,\n            highlighted ? context.classNames.selectedState : context.classNames.highlightedState,\n          );\n        }\n      }\n\n      break;\n    }\n\n    default: {\n      update = false;\n      break;\n    }\n  }\n\n  return { state, update };\n}\n"
  },
  {
    "path": "src/scripts/search/fuse.ts",
    "content": "// eslint-disable-next-line import/no-named-default\nimport { default as FuseFull, IFuseOptions } from 'fuse.js';\n// eslint-disable-next-line import/no-named-default\nimport { default as FuseBasic } from 'fuse.js/basic';\nimport { Options } from '../interfaces/options';\nimport { Searcher, SearchResult } from '../interfaces/search';\nimport { searchFuse } from '../interfaces/build-flags';\n\nexport class SearchByFuse<T extends object> implements Searcher<T> {\n  _fuseOptions: IFuseOptions<T>;\n\n  _haystack: T[] = [];\n\n  _fuse: FuseFull<T> | FuseBasic<T> | undefined;\n\n  constructor(config: Options) {\n    this._fuseOptions = {\n      ...config.fuseOptions,\n      keys: [...config.searchFields],\n      includeMatches: true,\n    };\n  }\n\n  index(data: T[]): void {\n    this._haystack = data;\n    if (this._fuse) {\n      this._fuse.setCollection(data);\n    }\n  }\n\n  reset(): void {\n    this._haystack = [];\n    this._fuse = undefined;\n  }\n\n  isEmptyIndex(): boolean {\n    return !this._haystack.length;\n  }\n\n  search(needle: string): SearchResult<T>[] {\n    if (!this._fuse) {\n      if (searchFuse === 'full') {\n        this._fuse = new FuseFull<T>(this._haystack, this._fuseOptions);\n      } else {\n        this._fuse = new FuseBasic<T>(this._haystack, this._fuseOptions);\n      }\n    }\n\n    const results = this._fuse.search(needle);\n\n    return results.map((value, i): SearchResult<T> => {\n      return {\n        item: value.item,\n        score: value.score || 0,\n        rank: i + 1, // If value.score is used for sorting, this can create non-stable sorts!\n      };\n    });\n  }\n}\n"
  },
  {
    "path": "src/scripts/search/index.ts",
    "content": "import { Options } from '../interfaces';\nimport { Searcher } from '../interfaces/search';\nimport { SearchByPrefixFilter } from './prefix-filter';\nimport { SearchByFuse } from './fuse';\nimport { SearchByKMP } from './kmp';\nimport { searchFuse, searchKMP } from '../interfaces/build-flags';\n\nexport function getSearcher<T extends object>(config: Options): Searcher<T> {\n  if (searchFuse && !searchKMP) {\n    return new SearchByFuse<T>(config);\n  }\n  if (searchKMP) {\n    return new SearchByKMP<T>(config);\n  }\n\n  return new SearchByPrefixFilter<T>(config);\n}\n"
  },
  {
    "path": "src/scripts/search/kmp.ts",
    "content": "import { Options } from '../interfaces';\nimport { Searcher, SearchResult } from '../interfaces/search';\n\nfunction kmpSearch(pattern: string, text: string): number {\n  if (pattern.length === 0) {\n    return 0; // Immediate match\n  }\n\n  // Compute longest suffix-prefix table\n  const lsp = [0]; // Base case\n  for (let i = 1; i < pattern.length; i++) {\n    let j = lsp[i - 1]; // Start by assuming we're extending the previous LSP\n    while (j > 0 && pattern.charAt(i) !== pattern.charAt(j)) {\n      j = lsp[j - 1];\n    }\n    if (pattern.charAt(i) === pattern.charAt(j)) {\n      j++;\n    }\n    lsp.push(j);\n  }\n\n  // Walk through text string\n  let j = 0; // Number of chars matched in pattern\n  for (let i = 0; i < text.length; i++) {\n    while (j > 0 && text.charAt(i) !== pattern.charAt(j)) {\n      j = lsp[j - 1]; // Fall back in the pattern\n    }\n    if (text.charAt(i) === pattern.charAt(j)) {\n      j++; // Next char matched, increment position\n      if (j === pattern.length) {\n        return i - (j - 1);\n      }\n    }\n  }\n\n  return -1; // Not found\n}\n\nexport class SearchByKMP<T extends object> implements Searcher<T> {\n  _fields: string[];\n\n  _haystack: T[] = [];\n\n  constructor(config: Options) {\n    this._fields = config.searchFields;\n  }\n\n  index(data: T[]): void {\n    this._haystack = data;\n  }\n\n  reset(): void {\n    this._haystack = [];\n  }\n\n  isEmptyIndex(): boolean {\n    return !this._haystack.length;\n  }\n\n  search(_needle: string): SearchResult<T>[] {\n    const fields = this._fields;\n    if (!fields || !fields.length || !_needle) {\n      return [];\n    }\n    const needle = _needle.toLowerCase();\n\n    const results: SearchResult<T>[] = [];\n\n    let count = 0;\n    for (let i = 0, j = this._haystack.length; i < j; i++) {\n      const obj = this._haystack[i];\n      for (let k = 0, l = this._fields.length; k < l; k++) {\n        const field = this._fields[k];\n        if (field in obj && kmpSearch(needle, (obj[field] as string).toLowerCase()) !== -1) {\n          results.push({\n            item: obj,\n            score: count,\n            rank: count + 1,\n          });\n          count++;\n          break;\n        }\n      }\n    }\n\n    return results;\n  }\n}\n"
  },
  {
    "path": "src/scripts/search/prefix-filter.ts",
    "content": "import { Options } from '../interfaces';\nimport { Searcher, SearchResult } from '../interfaces/search';\n\nexport class SearchByPrefixFilter<T extends object> implements Searcher<T> {\n  _fields: string[];\n\n  _haystack: T[] = [];\n\n  constructor(config: Options) {\n    this._fields = config.searchFields;\n  }\n\n  index(data: T[]): void {\n    this._haystack = data;\n  }\n\n  reset(): void {\n    this._haystack = [];\n  }\n\n  isEmptyIndex(): boolean {\n    return !this._haystack.length;\n  }\n\n  search(_needle: string): SearchResult<T>[] {\n    const fields = this._fields;\n    if (!fields || !fields.length || !_needle) {\n      return [];\n    }\n    const needle = _needle.toLowerCase();\n\n    return this._haystack\n      .filter((obj) => fields.some((field) => field in obj && (obj[field] as string).toLowerCase().startsWith(needle)))\n      .map((value, index): SearchResult<T> => {\n        return {\n          item: value,\n          score: index,\n          rank: index + 1,\n        };\n      });\n  }\n}\n"
  },
  {
    "path": "src/scripts/store/store.ts",
    "content": "import { AnyAction, Reducer, Store as IStore, StoreListener } from '../interfaces/store';\nimport { StateChangeSet, State } from '../interfaces/state';\nimport { ChoiceFull } from '../interfaces/choice-full';\nimport { GroupFull } from '../interfaces/group-full';\nimport { Options } from '../interfaces/options';\nimport items from '../reducers/items';\nimport groups from '../reducers/groups';\nimport choices from '../reducers/choices';\n\ntype ReducerList = { [K in keyof State]: Reducer<State[K]> };\n\nconst reducers: ReducerList = {\n  groups,\n  items,\n  choices,\n} as const;\n\nexport default class Store<T> implements IStore {\n  _state: State = this.defaultState;\n\n  _listeners: StoreListener[] = [];\n\n  _txn: number = 0;\n\n  _changeSet?: StateChangeSet;\n\n  _context: T;\n\n  constructor(context: T) {\n    this._context = context;\n  }\n\n  // eslint-disable-next-line class-methods-use-this\n  get defaultState(): State {\n    return {\n      groups: [],\n      items: [],\n      choices: [],\n    };\n  }\n\n  // eslint-disable-next-line class-methods-use-this\n  changeSet(init: boolean): StateChangeSet {\n    return {\n      groups: init,\n      items: init,\n      choices: init,\n    };\n  }\n\n  reset(): void {\n    this._state = this.defaultState;\n    const changes = this.changeSet(true);\n    if (this._txn) {\n      this._changeSet = changes;\n    } else {\n      this._listeners.forEach((l) => l(changes));\n    }\n  }\n\n  subscribe(onChange: StoreListener): this {\n    this._listeners.push(onChange);\n\n    return this;\n  }\n\n  dispatch(action: AnyAction): void {\n    const state = this._state;\n    let hasChanges = false;\n    const changes = this._changeSet || this.changeSet(false);\n\n    Object.keys(reducers).forEach((key: string) => {\n      const stateUpdate = (reducers[key] as Reducer<unknown>)(state[key], action, this._context);\n      if (stateUpdate.update) {\n        hasChanges = true;\n        changes[key] = true;\n        state[key] = stateUpdate.state;\n      }\n    });\n\n    if (hasChanges) {\n      if (this._txn) {\n        this._changeSet = changes;\n      } else {\n        this._listeners.forEach((l) => l(changes));\n      }\n    }\n  }\n\n  withTxn(func: () => void): void {\n    this._txn++;\n    try {\n      func();\n    } finally {\n      this._txn = Math.max(0, this._txn - 1);\n\n      if (!this._txn) {\n        const changeSet = this._changeSet;\n        if (changeSet) {\n          this._changeSet = undefined;\n          this._listeners.forEach((l) => l(changeSet));\n        }\n      }\n    }\n  }\n\n  /**\n   * Get store object\n   */\n  get state(): State {\n    return this._state;\n  }\n\n  /**\n   * Get items from store\n   */\n  get items(): ChoiceFull[] {\n    return this.state.items;\n  }\n\n  /**\n   * Get highlighted items from store\n   */\n  get highlightedActiveItems(): ChoiceFull[] {\n    return this.items.filter((item) => item.active && item.highlighted);\n  }\n\n  /**\n   * Get choices from store\n   */\n  get choices(): ChoiceFull[] {\n    return this.state.choices;\n  }\n\n  /**\n   * Get active choices from store\n   */\n  get activeChoices(): ChoiceFull[] {\n    return this.choices.filter((choice) => choice.active);\n  }\n\n  /**\n   * Get choices that can be searched (excluding placeholders or disabled choices)\n   */\n  get searchableChoices(): ChoiceFull[] {\n    const context = this._context as Options;\n\n    return this.choices.filter((choice) => !choice.placeholder && (context.searchDisabledChoices || !choice.disabled));\n  }\n\n  /**\n   * Get groups from store\n   */\n  get groups(): GroupFull[] {\n    return this.state.groups;\n  }\n\n  /**\n   * Get active groups from store\n   */\n  get activeGroups(): GroupFull[] {\n    return this.state.groups.filter((group) => {\n      const isActive = group.active && !group.disabled;\n      const hasActiveOptions = this.state.choices.some((choice) => choice.active && !choice.disabled);\n\n      return isActive && hasActiveOptions;\n    }, []);\n  }\n\n  inTxn(): boolean {\n    return this._txn > 0;\n  }\n\n  /**\n   * Get single choice by it's ID\n   */\n  getChoiceById(id: number): ChoiceFull | undefined {\n    return this.activeChoices.find((choice) => choice.id === id);\n  }\n\n  /**\n   * Get group by group id\n   */\n  getGroupById(id: number): GroupFull | undefined {\n    return this.groups.find((group) => group.id === id);\n  }\n}\n"
  },
  {
    "path": "src/scripts/templates.ts",
    "content": "/**\n * Helpers to create HTML elements used by Choices\n * Can be overridden by providing `callbackOnCreateTemplates` option.\n * `Choices.defaults.templates` allows access to the default template methods from `callbackOnCreateTemplates`\n */\n\nimport { ChoiceFull } from './interfaces/choice-full';\nimport { GroupFull } from './interfaces/group-full';\nimport { PassedElementType } from './interfaces/passed-element-type';\nimport { StringPreEscaped } from './interfaces/string-pre-escaped';\nimport {\n  getClassNames,\n  unwrapStringForRaw,\n  resolveNoticeFunction,\n  setElementHtml,\n  escapeForTemplate,\n  addClassesToElement,\n  removeClassesFromElement,\n  getChoiceForOutput,\n} from './lib/utils';\nimport { NoticeType, NoticeTypes, TemplateOptions, Templates as TemplatesInterface } from './interfaces/templates';\nimport { StringUntrusted } from './interfaces/string-untrusted';\n\nconst isEmptyObject = (obj: object): boolean => {\n  // eslint-disable-next-line no-restricted-syntax\n  for (const prop in obj) {\n    if (Object.prototype.hasOwnProperty.call(obj, prop)) {\n      return false;\n    }\n  }\n\n  return true;\n};\n\nconst assignCustomProperties = (el: HTMLElement, choice: ChoiceFull, withCustomProperties: boolean): void => {\n  const { dataset } = el;\n  const { customProperties, labelClass, labelDescription } = choice;\n\n  if (labelClass) {\n    dataset.labelClass = getClassNames(labelClass).join(' ');\n  }\n\n  if (labelDescription) {\n    dataset.labelDescription = unwrapStringForRaw(labelDescription);\n  }\n\n  if (withCustomProperties && customProperties) {\n    if (typeof customProperties === 'string') {\n      dataset.customProperties = customProperties;\n    } else if (typeof customProperties === 'object' && !isEmptyObject(customProperties)) {\n      dataset.customProperties = JSON.stringify(customProperties);\n    }\n  }\n};\n\nconst addAriaLabel = (docRoot: HTMLElement | ShadowRoot, id: string | undefined, element: HTMLElement): void => {\n  const label = id && docRoot.querySelector<HTMLElement>(`label[for='${id}']`);\n  const text = label && (label as HTMLElement).innerText;\n  if (text) {\n    element.setAttribute('aria-label', text);\n  }\n};\n\nconst templates: TemplatesInterface = {\n  containerOuter(\n    { classNames: { containerOuter } }: TemplateOptions,\n    dir: HTMLElement['dir'],\n    isSelectElement: boolean,\n    isSelectOneElement: boolean,\n    searchEnabled: boolean,\n    passedElementType: PassedElementType,\n    labelId: string,\n  ): HTMLDivElement {\n    const div = document.createElement('div');\n    addClassesToElement(div, containerOuter);\n\n    div.dataset.type = passedElementType;\n\n    if (dir) {\n      div.dir = dir;\n    }\n\n    if (isSelectOneElement) {\n      div.tabIndex = 0;\n    }\n\n    if (isSelectElement) {\n      div.setAttribute('role', searchEnabled ? 'combobox' : 'listbox');\n      if (searchEnabled) {\n        div.setAttribute('aria-autocomplete', 'list');\n      } else if (!labelId) {\n        addAriaLabel(this._docRoot, this.passedElement.element.id, div);\n      }\n\n      div.setAttribute('aria-haspopup', 'true');\n      div.setAttribute('aria-expanded', 'false');\n    }\n\n    if (labelId) {\n      div.setAttribute('aria-labelledby', labelId);\n    }\n\n    return div;\n  },\n\n  containerInner({ classNames: { containerInner } }: TemplateOptions): HTMLDivElement {\n    const div = document.createElement('div');\n    addClassesToElement(div, containerInner);\n\n    return div;\n  },\n\n  itemList(\n    { searchEnabled, classNames: { list, listSingle, listItems } }: TemplateOptions,\n    isSelectOneElement: boolean,\n  ): HTMLDivElement {\n    const div = document.createElement('div');\n    addClassesToElement(div, list);\n    addClassesToElement(div, isSelectOneElement ? listSingle : listItems);\n\n    if (this._isSelectElement && searchEnabled) {\n      div.setAttribute('role', 'listbox');\n    }\n\n    return div;\n  },\n\n  placeholder(\n    { allowHTML, classNames: { placeholder } }: TemplateOptions,\n    value: StringPreEscaped | string,\n  ): HTMLDivElement {\n    const div = document.createElement('div');\n    addClassesToElement(div, placeholder);\n    setElementHtml(div, allowHTML, value);\n\n    return div;\n  },\n\n  item(\n    {\n      allowHTML,\n      removeItemButtonAlignLeft,\n      removeItemIconText,\n      removeItemLabelText,\n      classNames: { item, button, highlightedState, itemSelectable, placeholder },\n    }: TemplateOptions,\n    choice: ChoiceFull,\n    removeItemButton: boolean,\n  ): HTMLDivElement {\n    const rawValue = unwrapStringForRaw(choice.value);\n    const div = document.createElement('div');\n    addClassesToElement(div, item);\n\n    if (choice.labelClass) {\n      const spanLabel = document.createElement('span');\n      setElementHtml(spanLabel, allowHTML, choice.label);\n      addClassesToElement(spanLabel, choice.labelClass);\n      div.appendChild(spanLabel);\n    } else {\n      setElementHtml(div, allowHTML, choice.label);\n    }\n\n    div.dataset.item = '';\n    div.dataset.id = choice.id as unknown as string;\n    div.dataset.value = rawValue;\n\n    assignCustomProperties(div, choice, true);\n\n    if (choice.disabled || this.containerOuter.isDisabled) {\n      div.setAttribute('aria-disabled', 'true');\n    }\n    if (this._isSelectElement) {\n      div.setAttribute('aria-selected', 'true');\n      div.setAttribute('role', 'option');\n    }\n\n    if (choice.placeholder) {\n      addClassesToElement(div, placeholder);\n      div.dataset.placeholder = '';\n    }\n\n    addClassesToElement(div, choice.highlighted ? highlightedState : itemSelectable);\n\n    if (removeItemButton) {\n      if (choice.disabled) {\n        removeClassesFromElement(div, itemSelectable);\n      }\n      div.dataset.deletable = '';\n\n      const removeButton = document.createElement('button');\n      removeButton.type = 'button';\n      addClassesToElement(removeButton, button);\n      const eventChoice = getChoiceForOutput(choice);\n      setElementHtml(removeButton, true, resolveNoticeFunction(removeItemIconText, choice.value, eventChoice));\n\n      const REMOVE_ITEM_LABEL = resolveNoticeFunction(removeItemLabelText, choice.value, eventChoice);\n      if (REMOVE_ITEM_LABEL) {\n        removeButton.setAttribute('aria-label', REMOVE_ITEM_LABEL);\n      }\n      removeButton.dataset.button = '';\n      if (removeItemButtonAlignLeft) {\n        div.insertAdjacentElement('afterbegin', removeButton);\n      } else {\n        div.appendChild(removeButton);\n      }\n    }\n\n    return div;\n  },\n\n  choiceList({ classNames: { list } }: TemplateOptions, isSelectOneElement: boolean): HTMLDivElement {\n    const div = document.createElement('div');\n    addClassesToElement(div, list);\n\n    if (!isSelectOneElement) {\n      div.setAttribute('aria-multiselectable', 'true');\n    }\n    div.setAttribute('role', 'listbox');\n\n    return div;\n  },\n\n  choiceGroup(\n    { allowHTML, classNames: { group, groupHeading, itemDisabled } }: TemplateOptions,\n    { id, label, disabled }: GroupFull,\n  ): HTMLDivElement {\n    const rawLabel = unwrapStringForRaw(label);\n    const div = document.createElement('div');\n    addClassesToElement(div, group);\n    if (disabled) {\n      addClassesToElement(div, itemDisabled);\n    }\n\n    div.setAttribute('role', 'group');\n\n    div.dataset.group = '';\n    div.dataset.id = id as unknown as string;\n    div.dataset.value = rawLabel;\n\n    if (disabled) {\n      div.setAttribute('aria-disabled', 'true');\n    }\n\n    const heading = document.createElement('div');\n    addClassesToElement(heading, groupHeading);\n    setElementHtml(heading, allowHTML, label || '');\n    div.appendChild(heading);\n\n    return div;\n  },\n\n  choice(\n    {\n      allowHTML,\n      classNames: { item, itemChoice, itemSelectable, selectedState, itemDisabled, description, placeholder },\n    }: TemplateOptions,\n    choice: ChoiceFull,\n    selectText: string,\n    groupName?: string,\n  ): HTMLDivElement {\n    // eslint-disable-next-line prefer-destructuring\n    let label: string | StringUntrusted | StringPreEscaped = choice.label;\n    const rawValue = unwrapStringForRaw(choice.value);\n    const div = document.createElement('div');\n    div.id = choice.elementId as string;\n    addClassesToElement(div, item);\n    addClassesToElement(div, itemChoice);\n\n    if (groupName && typeof label === 'string') {\n      label = escapeForTemplate(allowHTML, label);\n      label += ` (${groupName})`;\n      label = { trusted: label };\n    }\n\n    let describedBy: HTMLElement = div;\n    if (choice.labelClass) {\n      const spanLabel = document.createElement('span');\n      setElementHtml(spanLabel, allowHTML, label);\n      addClassesToElement(spanLabel, choice.labelClass);\n      describedBy = spanLabel;\n      div.appendChild(spanLabel);\n    } else {\n      setElementHtml(div, allowHTML, label);\n    }\n\n    if (choice.labelDescription) {\n      const descId = `${choice.elementId}-description`;\n      describedBy.setAttribute('aria-describedby', descId);\n      const spanDesc = document.createElement('span');\n      setElementHtml(spanDesc, allowHTML, choice.labelDescription);\n      spanDesc.id = descId;\n      addClassesToElement(spanDesc, description);\n      div.appendChild(spanDesc);\n    }\n\n    if (choice.selected) {\n      addClassesToElement(div, selectedState);\n    }\n\n    if (choice.placeholder) {\n      addClassesToElement(div, placeholder);\n    }\n\n    div.setAttribute('role', choice.group ? 'treeitem' : 'option');\n\n    div.dataset.choice = '';\n    div.dataset.id = choice.id as unknown as string;\n    div.dataset.value = rawValue;\n    if (selectText) {\n      div.dataset.selectText = selectText;\n    }\n    if (choice.group) {\n      div.dataset.groupId = `${choice.group.id}`;\n    }\n\n    assignCustomProperties(div, choice, false);\n\n    if (choice.disabled) {\n      addClassesToElement(div, itemDisabled);\n      div.dataset.choiceDisabled = '';\n      div.setAttribute('aria-disabled', 'true');\n    } else {\n      addClassesToElement(div, itemSelectable);\n      div.dataset.choiceSelectable = '';\n      div.setAttribute('aria-selected', choice.selected ? 'true' : 'false');\n    }\n\n    return div;\n  },\n\n  input(\n    { classNames: { input, inputCloned }, labelId }: TemplateOptions,\n    placeholderValue: string | null,\n  ): HTMLInputElement {\n    const inp = document.createElement('input');\n    inp.type = 'search';\n    addClassesToElement(inp, input);\n    addClassesToElement(inp, inputCloned);\n    inp.autocomplete = 'off';\n    inp.autocapitalize = 'off';\n    inp.spellcheck = false;\n\n    inp.setAttribute('aria-autocomplete', 'list');\n    if (placeholderValue) {\n      inp.setAttribute('aria-label', placeholderValue);\n    } else if (!labelId) {\n      addAriaLabel(this._docRoot, this.passedElement.element.id, inp);\n    }\n\n    return inp;\n  },\n\n  dropdown({ classNames: { list, listDropdown } }: TemplateOptions): HTMLDivElement {\n    const div = document.createElement('div');\n\n    addClassesToElement(div, list);\n    addClassesToElement(div, listDropdown);\n    div.setAttribute('aria-expanded', 'false');\n\n    return div;\n  },\n\n  notice(\n    { classNames: { item, itemChoice, addChoice, noResults, noChoices, notice: noticeItem } }: TemplateOptions,\n    innerHTML: string,\n    type: NoticeType = NoticeTypes.generic,\n  ): HTMLDivElement {\n    const notice = document.createElement('div');\n    setElementHtml(notice, true, innerHTML);\n\n    addClassesToElement(notice, item);\n    addClassesToElement(notice, itemChoice);\n    addClassesToElement(notice, noticeItem);\n\n    // eslint-disable-next-line default-case\n    switch (type) {\n      case NoticeTypes.addChoice:\n        addClassesToElement(notice, addChoice);\n        break;\n      case NoticeTypes.noResults:\n        addClassesToElement(notice, noResults);\n        break;\n      case NoticeTypes.noChoices:\n        addClassesToElement(notice, noChoices);\n        break;\n    }\n\n    if (type === NoticeTypes.addChoice) {\n      notice.dataset.choiceSelectable = '';\n      notice.dataset.choice = '';\n    }\n\n    return notice;\n  },\n\n  option(choice: ChoiceFull): HTMLOptionElement {\n    // HtmlOptionElement's label value does not support HTML, so the avoid double escaping unwrap the untrusted string.\n    const labelValue = unwrapStringForRaw(choice.label);\n\n    const opt = new Option(labelValue, choice.value, false, choice.selected);\n    assignCustomProperties(opt, choice, true);\n\n    opt.disabled = choice.disabled;\n    if (choice.selected) {\n      opt.setAttribute('selected', '');\n    }\n\n    return opt;\n  },\n};\n\nexport default templates;\n"
  },
  {
    "path": "src/styles/base.scss",
    "content": "/* =============================================\n=            Generic styling                  =\n============================================= */\n\n:root {\n  --color-primary: #005F75;\n}\n\n@media (prefers-color-scheme: dark) {\n  :root {\n    /* Demo defaults */\n    --body-bg: #272a2b;\n    --text-color: #cacaca;\n    --color-primary: #38daff;\n    --section-bg: #181a1b;\n    --section-color: #cacaca;\n    --hr-border: #373a3d;\n    --choices-primary-color: #38daff;\n    --choices-item-color: black;\n    --choices-bg-color: #101010;\n    --choices-bg-color-dropdown: #101010;\n    --choices-keyline-color: #3b3e40;\n    --choices-bg-color-disabled: #181a1b;\n    --choices-item-disabled-color: #eee;\n    --choices-disabled-color: #2d2d2d;\n    --choices-highlighted-color: #16292d;\n    --choices-icon-cross: url(\"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjEiIHZpZXdCb3g9IjAgMCAyMSAyMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSIjMDAwIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0yLjU5Mi4wNDRsMTguMzY0IDE4LjM2NC0yLjU0OCAyLjU0OEwuMDQ0IDIuNTkyeiIvPjxwYXRoIGQ9Ik0wIDE4LjM2NEwxOC4zNjQgMGwyLjU0OCAyLjU0OEwyLjU0OCAyMC45MTJ6Ii8+PC9nPjwvc3ZnPg==\");\n    --choices-icon-cross-inverse: url(\"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjEiIHZpZXdCb3g9IjAgMCAyMSAyMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSIjRkZGIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0yLjU5Mi4wNDRsMTguMzY0IDE4LjM2NC0yLjU0OCAyLjU0OEwuMDQ0IDIuNTkyeiIvPjxwYXRoIGQ9Ik0wIDE4LjM2NEwxOC4zNjQgMGwyLjU0OCAyLjU0OEwyLjU0OCAyMC45MTJ6Ii8+PC9nPjwvc3ZnPg==\");\n\n    color-scheme: dark;\n  }\n\n  input, select {\n    color: #fff;\n  }\n}\n\n$global-guttering: 24px;\n$global-font-size-h1: 32px;\n$global-font-size-h2: 24px;\n$global-font-size-h3: 20px;\n$global-font-size-h4: 18px;\n$global-font-size-h5: 16px;\n$global-font-size-h6: 14px;\n\n* {\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n\n*,\n*::before,\n*::after {\n  box-sizing: border-box;\n}\n\nhtml,\nbody {\n  position: relative;\n  margin: 0;\n  width: 100%;\n  height: 100%;\n}\n\nbody {\n  font-family: \"Helvetica Neue\", Helvetica, Arial, \"Lucida Grande\", sans-serif;\n  font-size: 16px;\n  line-height: 1.4;\n  color: var(--text-color, #fff);\n  background-color: var(--body-bg, #333);\n  overflow-x: hidden;\n}\n\nlabel {\n  display: block;\n  margin-bottom: 8px;\n  font-size: 14px;\n  font-weight: 500;\n  cursor: pointer;\n}\n\np {\n  margin-top: 0;\n  margin-bottom: 8px;\n}\n\nhr {\n  display: block;\n  margin: $global-guttering * 1.25 0;\n  border: 0;\n  border-bottom: 1px solid var(--hr-border, #eaeaea);\n  height: 1px;\n}\n\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n  margin-top: 0;\n  margin-bottom: $global-guttering * 0.5;\n  font-weight: 400;\n  line-height: 1.2;\n}\n\na,\na:visited,\na:focus {\n  color: var(--link-color, #fff);\n  text-decoration: none;\n  font-weight: 600;\n}\n\n.form-control {\n  display: block;\n  width: 100%;\n  background-color: var(--form-bg, #f9f9f9);\n  padding: 12px;\n  border: 1px solid var(--form-boder, #ddd);\n  border-radius: 2.5px;\n  font-size: 14px;\n  appearance: none;\n  margin-bottom: $global-guttering;\n}\n\nh1,\n.h1 {\n  font-size: $global-font-size-h1;\n}\n\nh2,\n.h2 {\n  font-size: $global-font-size-h2;\n}\n\nh3,\n.h3 {\n  font-size: $global-font-size-h3;\n}\n\nh4,\n.h4 {\n  font-size: $global-font-size-h4;\n}\n\nh5,\n.h5 {\n  font-size: $global-font-size-h5;\n}\n\nh6,\n.h6 {\n  font-size: $global-font-size-h6;\n}\n\nlabel + p {\n  margin-top: -4px;\n}\n\n.container {\n  display: block;\n  margin: auto;\n  max-width: 40em;\n  padding: $global-guttering * 2;\n\n  @media (max-width: 620px) {\n    padding: 0;\n  }\n}\n\n.section {\n  background-color: var(--section-bg, #fff);\n  padding: $global-guttering;\n  color: var(--section-color, #333);\n\n  a,\n  a:visited,\n  a:focus {\n    color: var(--link-color-section, var(--color-primary));\n  }\n}\n\n.logo {\n  display: block;\n  margin-bottom: $global-guttering * 0.5;\n}\n\n.logo-img {\n  width: 100%;\n  height: auto;\n  display: inline-block;\n  max-width: 100%;\n  vertical-align: top;\n  padding: $global-guttering * 0.25 0;\n}\n\n.visible-ie {\n  display: none;\n}\n\n.push-bottom {\n  margin-bottom: $global-guttering;\n}\n\n.zero-bottom {\n  margin-bottom: 0;\n}\n\n.zero-top {\n  margin-top: 0;\n}\n\n.text-center {\n  text-align: center;\n}\n\n[data-test-hook] {\n  margin-bottom: $global-guttering;\n}\n\n/* =====  End of Section comment block  ====== */\n"
  },
  {
    "path": "src/styles/choices.scss",
    "content": "/* ===============================\n=            Choices            =\n=============================== */\n\n$choices-selector: \"choices\" !default;\n$choices-font-size-lg: 16px !default;\n$choices-font-size-md: 14px !default;\n$choices-font-size-sm: 12px !default;\n$choices-guttering: 24px !default;\n$choices-border-radius: 2.5px !default;\n$choices-border-radius-item: 20px !default;\n$choices-bg-color: #f9f9f9 !default;\n$choices-bg-color-disabled: #eaeaea !default;\n$choices-bg-color-dropdown: #fff !default;\n$choices-text-color: #333 !default;\n$choices-item-color: #fff !default;\n$choices-keyline-color: #ddd !default;\n$choices-primary-color: #005F75 !default;\n$choices-disabled-color: #eaeaea !default;\n$choices-item-disabled-color: #fff !default;\n$choices-invalid-color: #d33141 !default;\n$choices-highlighted-color: #f2f2f2 !default;\n$choices-highlight-color: $choices-primary-color !default;\n$choices-button-dimension: 8px !default;\n$choices-button-offset: 8px !default;\n$choices-icon-cross: url(\"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjEiIHZpZXdCb3g9IjAgMCAyMSAyMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSIjRkZGIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0yLjU5Mi4wNDRsMTguMzY0IDE4LjM2NC0yLjU0OCAyLjU0OEwuMDQ0IDIuNTkyeiIvPjxwYXRoIGQ9Ik0wIDE4LjM2NEwxOC4zNjQgMGwyLjU0OCAyLjU0OEwyLjU0OCAyMC45MTJ6Ii8+PC9nPjwvc3ZnPg==\") !default;\n$choices-icon-cross-inverse: url(\"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiIGhlaWdodD0iMjEiIHZpZXdCb3g9IjAgMCAyMSAyMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSIjMDAwIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0yLjU5Mi4wNDRsMTguMzY0IDE4LjM2NC0yLjU0OCAyLjU0OEwuMDQ0IDIuNTkyeiIvPjxwYXRoIGQ9Ik0wIDE4LjM2NEwxOC4zNjQgMGwyLjU0OCAyLjU0OEwyLjU0OCAyMC45MTJ6Ii8+PC9nPjwvc3ZnPg==\") !default;\n$choices-z-index: 1 !default;\n$choices-input-height: 44px !default;\n$choices-width: 100% !default;\n$choices-base-border: 1px solid !default;\n$choices-multiple-item-margin: 3.75px !default;\n$choices-multiple-item-padding: 4px 10px !default;\n$choices-dropdown-item-padding: 10px !default;\n$choices-list-single-padding: 4px 16px 4px 4px !default;\n$choices-input-margin-bottom: 5px;\n$choices-input-padding: 4px 0 4px 2px !default;\n$choices-inner-padding: 7.5px 7.5px 3.75px !default;\n$choices-inner-one-padding: 7.5px !default;\n$choices-arrow-size: 5px !default;\n$choices-arrow-margin-top: -2.5px !default;\n$choices-arrow-margin-top-open: -7.5px !default;\n$choices-arrow-right: 11.5px !default;\n$choices-button-line-height: 1 !default;\n$choices-button-border-radius: 0 !default;\n$choices-button-opacity: 0.75 !default;\n$choices-button-opacity-hover: 1 !default;\n$choices-placeholder-opacity: 0.5 !default;\n\n.#{$choices-selector} {\n  position: relative;\n  overflow: hidden;\n  margin-bottom: var(--choices-guttering, #{$choices-guttering});\n  font-size: var(--choices-font-size-lg, #{$choices-font-size-lg});\n\n  &:focus {\n    outline: none;\n  }\n\n  &:last-child {\n    margin-bottom: 0;\n  }\n\n  &.is-open {\n    overflow: visible;\n  }\n\n  &.is-disabled {\n    :is(.#{$choices-selector}__inner, .#{$choices-selector}__input) {\n      background-color: var(--choices-bg-color-disabled, #{$choices-bg-color-disabled});\n      cursor: not-allowed !important;\n      user-select: none;\n    }\n    .#{$choices-selector}__item {\n      cursor: not-allowed;\n      color: var(--choices-item-disabled-color, #{$choices-item-disabled-color});\n    }\n  }\n\n  [hidden] {\n    position: absolute;\n    inset: 0;\n    pointer-events: none;\n    opacity: 0;\n  }\n}\n\n.#{$choices-selector}[data-type*='select-one'] {\n  cursor: pointer;\n  .#{$choices-selector}__inner {\n    padding-bottom: var(--choices-inner-one-padding, #{$choices-inner-one-padding});\n  }\n  .#{$choices-selector}__input {\n    display: block;\n    width: var(--choices-width, #{$choices-width});\n    padding: var(--choices-dropdown-item-padding, #{$choices-dropdown-item-padding});\n    border-bottom: var(--choices-base-border, #{$choices-base-border}) var(--choices-keyline-color, #{$choices-keyline-color});\n    background-color: var(--choices-bg-color-dropdown, #{$choices-bg-color-dropdown});\n    margin: 0;\n  }\n  .#{$choices-selector}__button {\n    background-image: var(--choices-icon-cross-inverse, #{$choices-icon-cross-inverse});\n    padding: 0;\n    background-size: 8px;\n    position: absolute;\n    top: 50%;\n    right: 0;\n    margin-top: -10px;\n    margin-right: 25px;\n    height: 20px;\n    width: 20px;\n    border-radius: 10em;\n    opacity: 0.25;\n\n    &:is(:hover, :focus) {\n      opacity: var(--choices-button-opacity-hover, #{$choices-button-opacity-hover});\n    }\n\n    &:focus {\n      box-shadow: 0 0 0 2px var(--choices-highlight-color, #{$choices-highlight-color});\n    }\n  }\n  .#{$choices-selector}__item[data-placeholder] .#{$choices-selector}__button {\n    display: none;\n  }\n\n  &::after {\n    content: \"\";\n    height: 0;\n    width: 0;\n    border-style: solid;\n    border-color: var(--choices-text-color, #{$choices-text-color}) transparent transparent transparent;\n    border-width: var(--choices-arrow-size, #{$choices-arrow-size});\n    position: absolute;\n    right: var(--choices-arrow-right, #{$choices-arrow-right});\n    top: 50%;\n    margin-top: var(--choices-arrow-margin-top, #{$choices-arrow-margin-top});\n    pointer-events: none;\n  }\n\n  &.is-open::after {\n    border-color: transparent transparent var(--choices-text-color, #{$choices-text-color});\n    margin-top: var(--choices-arrow-margin-top-open, #{$choices-arrow-margin-top-open});\n  }\n\n  &[dir=\"rtl\"] {\n    &::after {\n      left: 11.5px;\n      right: auto;\n    }\n    .#{$choices-selector}__button {\n      right: auto;\n      left: 0;\n      margin-left: 25px;\n      margin-right: 0;\n    }\n  }\n}\n\n.#{$choices-selector}:is([data-type*='select-multiple'], [data-type*='text']) {\n  .#{$choices-selector}__inner {\n    cursor: text;\n  }\n  .#{$choices-selector}__button {\n    position: relative;\n    display: inline-block;\n    margin: 0 calc(var(--choices-button-offset, #{$choices-button-offset}) * -0.5) 0 var(--choices-button-offset, #{$choices-button-offset});\n    padding-left: calc(var(--choices-button-offset, #{$choices-button-offset}) * 2);\n    border-left: 1px solid color-mix(in srgb, var(--choices-primary-color, #{$choices-primary-color}) 90%, var(--choices-darken, black));\n    background-image: var(--choices-icon-cross, #{$choices-icon-cross});\n    background-size: var(--choices-button-dimension, #{$choices-button-dimension});\n    width: var(--choices-button-dimension, #{$choices-button-dimension});\n    line-height: var(--choices-button-line-height, #{$choices-button-line-height});\n    border-radius: var(--choices-button-border-radius, #{$choices-button-border-radius});\n    opacity: var(--choices-button-opacity, #{$choices-button-opacity});\n\n    &:is(:hover, :focus) {\n      --choices-button-opacity: var(--choices-button-opacity-hover, #{$choices-button-opacity-hover});\n    }\n  }\n}\n\n.#{$choices-selector}__inner {\n  display: inline-block;\n  vertical-align: top;\n  width: var(--choices-width, #{$choices-width});\n  background-color: var(--choices-bg-color, #{$choices-bg-color});\n  padding: var(--choices-inner-padding, #{$choices-inner-padding});;\n  border: var(--choices-base-border, #{$choices-base-border}) var(--choices-keyline-color, #{$choices-keyline-color});\n  border-radius: var(--choices-border-radius, #{$choices-border-radius});\n  font-size: var(--choices-font-size-md, #{$choices-font-size-md});\n  min-height: var(--choices-input-height, #{$choices-input-height});\n  overflow: hidden;\n\n  .is-focused &,\n  .is-open & {\n    border-color: color-mix(in srgb, var(--choices-keyline-color, #{$choices-keyline-color}) 85%, var(--choices-darken, black));\n  }\n\n  .is-open & {\n    border-radius: var(--choices-border-radius, #{$choices-border-radius}) var(--choices-border-radius, #{$choices-border-radius}) 0 0;\n  }\n\n  .is-invalid & {\n    border-color: var(--choices-invalid-color, #{$choices-invalid-color});\n  }\n\n  .is-flipped.is-open & {\n    border-radius: 0 0 var(--choices-border-radius, #{$choices-border-radius}) var(--choices-border-radius, #{$choices-border-radius});\n  }\n}\n\n.#{$choices-selector}__list {\n  margin: 0;\n  padding-left: 0;\n  list-style: none;\n\n  &[aria-expanded] {\n    @extend %choices-dropdown;\n  }\n}\n\n.#{$choices-selector}__list--single {\n  display: inline-block;\n  padding: var(--choices-list-single-padding, #{$choices-list-single-padding});\n  width: var(--choices-width, #{$choices-width});\n\n  [dir=\"rtl\"] & {\n    padding-right: 4px;\n    padding-left: 16px;\n  }\n  .#{$choices-selector}__item {\n    width: var(--choices-width, #{$choices-width});\n  }\n}\n\n.#{$choices-selector}__list--multiple {\n  display: inline;\n  .#{$choices-selector}__item {\n    display: inline-block;\n    vertical-align: middle;\n    border-radius: var(--choices-border-radius-item, #{$choices-border-radius-item});\n    padding: var(--choices-multiple-item-padding, #{$choices-multiple-item-padding});\n    font-size: var(--choices-font-size-sm, #{$choices-font-size-sm});\n    font-weight: 500;\n    margin-right: var(--choices-multiple-item-margin, #{$choices-multiple-item-margin});\n    margin-bottom: var(--choices-multiple-item-margin, #{$choices-multiple-item-margin});\n    background-color: var(--choices-primary-color, #{$choices-primary-color});\n    border: 1px solid color-mix(in srgb, var(--choices-primary-color, #{$choices-primary-color}) 95%, var(--choices-darken, black));\n    color: var(--choices-item-color, #{$choices-item-color});\n    word-break: break-all;\n    box-sizing: border-box;\n\n    &[data-deletable] {\n      padding-right: 5px;\n    }\n\n    [dir=\"rtl\"] & {\n      margin-right: 0;\n      margin-left: var(--choices-multiple-item-margin, #{$choices-multiple-item-margin});\n    }\n\n    &.is-highlighted {\n      background-color: color-mix(in srgb, var(--choices-primary-color, #{$choices-primary-color}) 95%, var(--choices-darken, black));\n      border: 1px solid color-mix(in srgb, var(--choices-primary-color, #{$choices-primary-color}) 90%, var(--choices-darken, black));\n    }\n\n    .is-disabled & {\n      background-color: color-mix(in srgb, var(--choices-disabled-color, #{$choices-disabled-color}) 75%, var(--choices-darken, black));\n      border: 1px solid color-mix(in srgb, var(--choices-disabled-color, #{$choices-disabled-color}) 65%, var(--choices-darken, black));\n    }\n  }\n}\n\n%choices-dropdown {\n  display: none;\n  z-index: var(--choices-z-index, #{$choices-z-index});\n  position: absolute;\n  width: var(--choices-width, #{$choices-width});\n  background-color: var(--choices-bg-color-dropdown, #{$choices-bg-color-dropdown});\n  border: var(--choices-base-border, #{$choices-base-border}) var(--choices-keyline-color, #{$choices-keyline-color});\n  top: 100%;\n  margin-top: -1px;\n  border-bottom-left-radius: var(--choices-border-radius, #{$choices-border-radius});\n  border-bottom-right-radius: var(--choices-border-radius, #{$choices-border-radius});\n  overflow: hidden;\n  word-break: break-all;\n\n  &.is-active {\n    display: block;\n  }\n\n  .is-open & {\n    border-color: color-mix(in srgb, var(--choices-keyline-color, #{$choices-keyline-color}) 85%, var(--choices-darken, black));\n  }\n\n  .is-flipped & {\n    top: auto;\n    bottom: 100%;\n    margin-top: 0;\n    margin-bottom: -1px;\n    border-radius: 0.25rem 0.25rem 0 0;\n  }\n  .#{$choices-selector}__list {\n    position: relative;\n    max-height: 300px;\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    will-change: scroll-position;\n  }\n  .#{$choices-selector}__item {\n    position: relative;\n    padding: var(--choices-dropdown-item-padding, #{$choices-dropdown-item-padding});\n    font-size: var(--choices-font-size-md, #{$choices-font-size-md});\n\n    [dir=\"rtl\"] & {\n      text-align: right;\n    }\n  }\n  .#{$choices-selector}__item--selectable {\n    &.is-highlighted[data-select-text] {\n      @media (min-width: 640px) {\n        padding-right: 100px;\n\n        &::after {\n          content: attr(data-select-text);\n          font-size: var(--choices-font-size-sm, #{$choices-font-size-sm});\n          position: absolute;\n          right: 10px;\n          top: 50%;\n          transform: translateY(-50%);\n        }\n\n        [dir=\"rtl\"] & {\n          text-align: right;\n          padding-left: 100px;\n          padding-right: 10px;\n\n          &::after {\n            right: auto;\n            left: 10px;\n          }\n        }\n      }\n    }\n\n    // Reset the content on selected option\n    &.is-selected {\n      &::after {\n        content: none !important;\n      }\n    }\n\n    &.is-selected,\n    &.is-highlighted {\n      background-color: var(--choices-highlighted-color, #{$choices-highlighted-color});\n    }\n  }\n}\n\n.#{$choices-selector}__list--dropdown {\n  @extend %choices-dropdown;\n}\n\n.#{$choices-selector}__item {\n  cursor: default;\n}\n\n.#{$choices-selector}__item--selectable {\n  cursor: pointer;\n}\n\n.#{$choices-selector}__item--disabled {\n  cursor: not-allowed;\n  user-select: none;\n  opacity: 0.5;\n}\n\n.#{$choices-selector}__heading {\n  font-weight: 600;\n  font-size: $choices-font-size-sm;\n  padding: 10px;\n  border-bottom: 1px solid color-mix(in srgb, var(--choices-keyline-color, #{$choices-keyline-color}) 90%, var(--choices-lighten, white));\n  color: gray;\n}\n\n.#{$choices-selector}__button {\n  text-indent: -9999px;\n  appearance: none;\n  border: 0;\n  background-color: transparent;\n  background-repeat: no-repeat;\n  background-position: center;\n  cursor: pointer;\n\n  &:focus {\n    outline: none;\n  }\n}\n\n.#{$choices-selector}__input {\n  display: inline-block;\n  vertical-align: baseline;\n  background-color: var(--choices-bg-color, #{$choices-bg-color});\n  font-size: var(--choices-font-size-md, #{$choices-font-size-md});\n  margin-bottom: var(--choices-input-margin-bottom, #{$choices-input-margin-bottom});\n  border: 0;\n  border-radius: 0;\n  max-width: var(--choices-width, #{$choices-width});\n  padding: var(--choices-input-padding, #{$choices-input-padding});\n\n  &:focus {\n    outline: 0;\n  }\n\n  &::-webkit-search-decoration,\n  &::-webkit-search-cancel-button,\n  &::-webkit-search-results-button,\n  &::-webkit-search-results-decoration {\n    display: none;\n  }\n\n  &::-ms-clear,\n  &::-ms-reveal {\n    display: none;\n    width: 0;\n    height: 0;\n  }\n\n  [dir=\"rtl\"] & {\n    padding-right: 2px;\n    padding-left: 0;\n  }\n}\n\n.#{$choices-selector}__placeholder {\n  opacity: var(--choices-placeholder-opacity, #{$choices-placeholder-opacity});\n}\n\n/* =====  End of Choices  ====== */\n"
  },
  {
    "path": "src/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"es6\",\n    \"lib\": [\"es2017\", \"dom\"],\n    \"target\": \"es5\",\n    \"moduleResolution\": \"bundler\",\n    \"allowSyntheticDefaultImports\": true,\n    \"resolveJsonModule\": true,\n    \"esModuleInterop\": true,\n    \"strict\": false,\n    \"noImplicitAny\": false,\n    \"allowJs\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"strictNullChecks\": true,\n    \"newLine\": \"lf\",\n    \"declaration\": false,\n    \"declarationMap\": false\n  },\n  \"include\": [\".\"],\n  \"exclude\": [\"**/node_modules\", \"**/public\"]\n}"
  },
  {
    "path": "test/scripts/actions/choices.test.ts",
    "content": "import { expect } from 'chai';\nimport * as actions from '../../../src/scripts/actions/choices';\nimport { cloneObject } from '../../../src/scripts/lib/utils';\nimport { ChoiceFull } from '../../../src/scripts/interfaces/choice-full';\nimport { ActionType } from '../../../src';\nimport { stringToHtmlClass } from '../../../src/scripts/lib/choice-input';\n\ndescribe('actions/choices', () => {\n  const choice: ChoiceFull = {\n    highlighted: false,\n    value: 'test',\n    label: 'test',\n    id: 1,\n    groupId: 1,\n    score: 0,\n    rank: 0,\n    disabled: false,\n    elementId: '1',\n    labelClass: stringToHtmlClass('test foo--bar'),\n    labelDescription: 'test',\n    customProperties: {\n      test: true,\n    },\n    placeholder: true,\n    active: false,\n    selected: false,\n  };\n\n  describe('addChoice action', () => {\n    it('returns ADD_CHOICE action', () => {\n      const expectedAction: actions.AddChoiceAction = {\n        type: ActionType.ADD_CHOICE,\n        choice,\n      };\n\n      expect(actions.addChoice(cloneObject(choice))).to.deep.equal(expectedAction);\n    });\n  });\n\n  describe('filterChoices action', () => {\n    it('returns FILTER_CHOICES action', () => {\n      const results = Array(10);\n      const expectedAction: actions.FilterChoicesAction = {\n        type: ActionType.FILTER_CHOICES,\n        results,\n      };\n\n      expect(actions.filterChoices(results)).to.deep.equal(expectedAction);\n    });\n  });\n\n  describe('activateChoices action', () => {\n    describe('not passing active parameter', () => {\n      it('returns ACTIVATE_CHOICES action', () => {\n        const expectedAction: actions.ActivateChoicesAction = {\n          type: ActionType.ACTIVATE_CHOICES,\n          active: true,\n        };\n\n        expect(actions.activateChoices()).to.deep.equal(expectedAction);\n      });\n    });\n\n    describe('passing active parameter', () => {\n      it('returns ACTIVATE_CHOICES action', () => {\n        const active = true;\n        const expectedAction: actions.ActivateChoicesAction = {\n          type: ActionType.ACTIVATE_CHOICES,\n          active,\n        };\n\n        expect(actions.activateChoices(active)).to.deep.equal(expectedAction);\n      });\n    });\n  });\n\n  describe('removeChoice action', () => {\n    it('returns REMOVE_CHOICE action', () => {\n      const expectedAction: actions.RemoveChoiceAction = {\n        type: ActionType.REMOVE_CHOICE,\n        choice,\n      };\n\n      expect(actions.removeChoice(cloneObject(choice))).to.deep.equal(expectedAction);\n    });\n  });\n\n  describe('clearChoices action', () => {\n    it('returns CLEAR_CHOICES action', () => {\n      const expectedAction: actions.ClearChoicesAction = {\n        type: ActionType.CLEAR_CHOICES,\n      };\n\n      expect(actions.clearChoices()).to.deep.equal(expectedAction);\n    });\n  });\n});\n"
  },
  {
    "path": "test/scripts/actions/groups.test.ts",
    "content": "import { expect } from 'chai';\nimport * as actions from '../../../src/scripts/actions/groups';\nimport { GroupFull } from '../../../src/scripts/interfaces/group-full';\nimport { cloneObject } from '../../../src/scripts/lib/utils';\nimport { ActionType } from '../../../src';\n\ndescribe('actions/groups', () => {\n  describe('addGroup action', () => {\n    it('returns ADD_GROUP action', () => {\n      const group: GroupFull = {\n        label: 'test',\n        id: 1,\n        active: false,\n        disabled: false,\n        choices: [],\n      };\n\n      const expectedAction: actions.AddGroupAction = {\n        type: ActionType.ADD_GROUP,\n        group: cloneObject(group),\n      };\n\n      expect(actions.addGroup(group)).to.deep.equal(expectedAction);\n    });\n  });\n});\n"
  },
  {
    "path": "test/scripts/actions/items.test.ts",
    "content": "import { expect } from 'chai';\nimport * as actions from '../../../src/scripts/actions/items';\nimport { cloneObject } from '../../../src/scripts/lib/utils';\nimport { ChoiceFull } from '../../../src/scripts/interfaces/choice-full';\nimport { ActionType } from '../../../src';\n\ndescribe('actions/items', () => {\n  const item: ChoiceFull = {\n    highlighted: false,\n    active: false,\n    disabled: false,\n    selected: false,\n    value: 'test',\n    label: 'test',\n    id: 1,\n    groupId: 1,\n    score: 0,\n    rank: 0,\n    customProperties: { test: true },\n    placeholder: true,\n  };\n\n  describe('addItem action', () => {\n    it('returns ADD_ITEM action', () => {\n      const expectedAction: actions.AddItemAction = {\n        type: ActionType.ADD_ITEM,\n        item,\n      };\n\n      expect(actions.addItem(cloneObject(item))).to.deep.equal(expectedAction);\n    });\n  });\n\n  describe('removeItem action', () => {\n    it('returns REMOVE_ITEM action', () => {\n      const expectedAction: actions.RemoveItemAction = {\n        type: ActionType.REMOVE_ITEM,\n        item,\n      };\n\n      expect(actions.removeItem(cloneObject(item))).to.deep.equal(expectedAction);\n    });\n  });\n\n  describe('highlightItem action', () => {\n    it('returns HIGHLIGHT_ITEM action', () => {\n      const highlighted = true;\n      const expectedAction: actions.HighlightItemAction = {\n        type: ActionType.HIGHLIGHT_ITEM,\n        item,\n        highlighted,\n      };\n\n      expect(actions.highlightItem(cloneObject(item), highlighted)).to.deep.equal(expectedAction);\n    });\n  });\n});\n"
  },
  {
    "path": "test/scripts/choices.test.ts",
    "content": "import { expect } from 'chai';\nimport { spy, stub } from 'sinon';\n\nimport sinonChai from 'sinon-chai';\nimport Choices, { DEFAULT_CONFIG, ActionType, EventType, KeyCodeMap, InputChoice, InputGroup } from '../../src';\nimport { WrappedSelect, WrappedInput } from '../../src/scripts/components/index';\nimport { removeItem } from '../../src/scripts/actions/items';\nimport templates from '../../src/scripts/templates';\nimport { ChoiceFull } from '../../src/scripts/interfaces/choice-full';\nimport { SearchByFuse } from '../../src/scripts/search/fuse';\nimport { SearchByKMP } from '../../src/scripts/search/kmp';\nimport { SearchByPrefixFilter } from '../../src/scripts/search/prefix-filter';\n\nchai.use(sinonChai);\n\ndescribe('choices', () => {\n  let instance;\n  let output;\n  let passedElement;\n\n  beforeEach(() => {\n    passedElement = document.createElement('input');\n    passedElement.type = 'text';\n    passedElement.className = 'js-choices';\n    document.body.appendChild(passedElement);\n\n    instance = new Choices(passedElement, { allowHTML: true });\n  });\n\n  afterEach(() => {\n    output = null;\n    instance = null;\n  });\n\n  describe('constructor', () => {\n    describe('config', () => {\n      describe('not passing config options', () => {\n        it('uses the default config', () => {\n          document.body.innerHTML = `\n          <input data-choice type=\"text\" id=\"input-1\" />\n          `;\n\n          instance = new Choices();\n\n          expect(instance.config).to.deep.equal({\n            ...DEFAULT_CONFIG,\n            searchEnabled: false,\n            closeDropdownOnSelect: true,\n            renderSelectedChoices: false,\n            searchRenderSelectedChoices: true,\n          });\n        });\n      });\n\n      describe('passing config options', () => {\n        it('merges the passed config with the default config', () => {\n          document.body.innerHTML = `\n          <input data-choice type=\"text\" id=\"input-1\" />\n          `;\n\n          const config = {\n            allowHTML: true,\n            renderChoiceLimit: 5,\n          };\n          instance = new Choices('[data-choice]', config);\n\n          expect(instance.config).to.deep.equal({\n            ...DEFAULT_CONFIG,\n            searchEnabled: false,\n            closeDropdownOnSelect: true,\n            renderSelectedChoices: false,\n            searchRenderSelectedChoices: true,\n            ...config,\n          });\n        });\n\n        describe('passing the searchEnabled config option with a value of false', () => {\n          describe('passing a select-multiple element', () => {\n            it('sets searchEnabled to true', () => {\n              document.body.innerHTML = `\n              <select data-choice multiple></select>\n              `;\n\n              instance = new Choices('[data-choice]', {\n                allowHTML: true,\n                searchEnabled: true,\n              });\n\n              expect(instance.config.searchEnabled).to.equal(true);\n            });\n            it('sets searchEnabled to false', () => {\n              document.body.innerHTML = `\n              <select data-choice multiple></select>\n              `;\n\n              instance = new Choices('[data-choice]', {\n                allowHTML: true,\n                searchEnabled: false,\n              });\n\n              expect(instance.config.searchEnabled).to.equal(false);\n            });\n          });\n        });\n\n        describe('passing the renderSelectedChoices config option with an unexpected value', () => {\n          it('sets renderSelectedChoices to \"auto\"', () => {\n            document.body.innerHTML = `\n            <select data-choice multiple></select>\n            `;\n\n            instance = new Choices('[data-choice]', {\n              allowHTML: true,\n              renderSelectedChoices: 'test' as any,\n            });\n\n            expect(instance.config.renderSelectedChoices).to.equal(false);\n          });\n        });\n\n        describe('passing the searchRenderSelectedChoices config option with false', () => {\n          it('keeps searchRenderSelectedChoices as false', () => {\n            document.body.innerHTML = `\n            <select data-choice multiple></select>\n            `;\n\n            instance = new Choices('[data-choice]', {\n              allowHTML: true,\n              searchRenderSelectedChoices: false,\n            });\n\n            expect(instance.config.searchRenderSelectedChoices).to.equal(false);\n          });\n        });\n      });\n    });\n\n    describe('not passing an element', () => {\n      it('returns a Choices instance for the first element with a \"data-choice\" attribute', () => {\n        document.body.innerHTML = `\n        <input data-choice type=\"text\" id=\"input-1\" />\n        <input data-choice type=\"text\" id=\"input-2\" />\n        <input data-choice type=\"text\" id=\"input-3\" />\n        `;\n\n        const inputs = document.querySelectorAll<HTMLElement>('[data-choice]');\n        expect(inputs.length).to.equal(3);\n\n        instance = new Choices(undefined, { allowHTML: true });\n\n        expect(instance.passedElement.element.id).to.equal(inputs[0].id);\n      });\n\n      describe('when an element cannot be found in the DOM', () => {\n        it('throws an error', () => {\n          document.body.innerHTML = ``;\n          expect(() => new Choices(undefined, { allowHTML: true })).to.throw(\n            TypeError,\n            'Selector [data-choice] failed to find an element',\n          );\n        });\n      });\n\n      describe('when an element is not of the expected type', () => {\n        it('throws an error', () => {\n          document.body.innerHTML = `<div [data-choice]></div>`;\n          expect(() => new Choices(undefined, { allowHTML: true })).to.throw(\n            TypeError,\n            'Selector [data-choice] failed to find an element',\n          );\n        });\n      });\n    });\n\n    describe('passing an element', () => {\n      describe('passing an element that has not been initialised with Choices', () => {\n        beforeEach(() => {\n          document.body.innerHTML = `\n          <input type=\"text\" id=\"input-1\" />\n          `;\n        });\n\n        it('sets the initialised flag to true', () => {\n          instance = new Choices('#input-1', { allowHTML: true });\n          expect(instance.initialised).to.equal(true);\n        });\n\n        it('intialises', () => {\n          const initSpy = spy();\n          // initialise with the same element\n          instance = new Choices('#input-1', {\n            allowHTML: true,\n            silent: true,\n            callbackOnInit: initSpy,\n          });\n\n          expect(initSpy.called).to.equal(true);\n        });\n      });\n\n      describe('passing an element that has already be initialised with Choices', () => {\n        beforeEach(() => {\n          document.body.innerHTML = `\n          <input type=\"text\" id=\"input-1\" />\n          `;\n\n          // initialise once\n          new Choices('#input-1', { allowHTML: true, silent: true });\n        });\n\n        it('sets the initialised flag to true', () => {\n          // initialise with the same element\n          instance = new Choices('#input-1', { allowHTML: true, silent: true });\n\n          expect(instance.initialised).to.equal(true);\n        });\n\n        it('does not reinitialise', () => {\n          const initSpy = spy();\n          // initialise with the same element\n          instance = new Choices('#input-1', {\n            allowHTML: true,\n            silent: true,\n            callbackOnInit: initSpy,\n          });\n\n          expect(initSpy.called).to.equal(false);\n        });\n      });\n\n      describe(`passing an element as a DOMString`, () => {\n        describe('passing a input element type', () => {\n          it('sets the \"passedElement\" instance property as an instance of WrappedInput', () => {\n            document.body.innerHTML = `\n            <input data-choice type=\"text\" id=\"input-1\" />\n            `;\n\n            instance = new Choices('[data-choice]', { allowHTML: true });\n\n            expect(instance.passedElement).to.be.an.instanceOf(WrappedInput);\n          });\n        });\n\n        describe('passing a select element type', () => {\n          it('sets the \"passedElement\" instance property as an instance of WrappedSelect', () => {\n            document.body.innerHTML = `\n            <select data-choice id=\"select-1\"></select>\n            `;\n\n            instance = new Choices('[data-choice]', { allowHTML: true });\n\n            expect(instance.passedElement).to.be.an.instanceOf(WrappedSelect);\n          });\n        });\n      });\n\n      describe(`passing an element as a HTMLElement`, () => {\n        describe('passing a input element type', () => {\n          it('sets the \"passedElement\" instance property as an instance of WrappedInput', () => {\n            document.body.innerHTML = `\n            <input data-choice type=\"text\" id=\"input-1\" />\n            `;\n\n            instance = new Choices('[data-choice]', { allowHTML: true });\n\n            expect(instance.passedElement).to.be.an.instanceOf(WrappedInput);\n          });\n        });\n\n        describe('passing a select element type', () => {\n          it('sets the \"passedElement\" instance property as an instance of WrappedSelect', () => {\n            document.body.innerHTML = `\n            <select data-choice id=\"select-1\"></select>\n            `;\n\n            instance = new Choices('[data-choice]', { allowHTML: true });\n\n            expect(instance.passedElement).to.be.an.instanceOf(WrappedSelect);\n          });\n        });\n      });\n\n      describe('passing an invalid element type', () => {\n        it('throws an TypeError', () => {\n          document.body.innerHTML = `\n          <div data-choice id=\"div-1\"></div>\n          `;\n          expect(() => new Choices('[data-choice]', { allowHTML: true })).to.throw(\n            TypeError,\n            'Expected one of the following types text|select-one|select-multiple',\n          );\n        });\n      });\n    });\n  });\n\n  describe('public methods', () => {\n    describe('init', () => {\n      const callbackOnInitSpy = spy();\n\n      beforeEach(() => {\n        instance = new Choices(passedElement, {\n          allowHTML: true,\n          callbackOnInit: callbackOnInitSpy,\n          silent: true,\n        });\n      });\n\n      describe('when already initialised', () => {\n        beforeEach(() => {\n          instance.initialised = true;\n          instance.init();\n        });\n\n        it(\"doesn't set initialise flag\", () => {\n          expect(instance.initialised).to.not.equal(false);\n        });\n      });\n\n      describe('not already initialised', () => {\n        let createTemplatesSpy;\n        let createInputSpy;\n        let storeSubscribeSpy;\n        let renderSpy;\n        let addEventListenersSpy;\n\n        beforeEach(() => {\n          createTemplatesSpy = spy(instance, '_createTemplates');\n          createInputSpy = spy(instance, '_createStructure');\n          storeSubscribeSpy = spy(instance._store, 'subscribe');\n          renderSpy = spy(instance, '_render');\n          addEventListenersSpy = spy(instance, '_addEventListeners');\n\n          instance.initialised = false;\n          instance.initialisedOK = undefined;\n          instance.init();\n        });\n\n        afterEach(() => {\n          createTemplatesSpy.restore();\n          createInputSpy.restore();\n          storeSubscribeSpy.restore();\n          renderSpy.restore();\n          addEventListenersSpy.restore();\n        });\n\n        it('sets initialise flag', () => {\n          expect(instance.initialised).to.equal(true);\n        });\n\n        it('creates templates', () => {\n          expect(createTemplatesSpy.called).to.equal(true);\n        });\n\n        it('creates input', () => {\n          expect(createInputSpy.called).to.equal(true);\n        });\n\n        it('subscribes to store with render method', () => {\n          expect(storeSubscribeSpy.called).to.equal(true);\n          expect(storeSubscribeSpy.lastCall.args[0]).to.equal(instance._render);\n        });\n\n        it('fire initial render with no items or choices', () => {\n          expect(renderSpy.called).to.equal(true);\n        });\n\n        it('adds event listeners', () => {\n          expect(addEventListenersSpy.called).to.equal(true);\n        });\n\n        it('fires callback', () => {\n          expect(callbackOnInitSpy.called).to.equal(true);\n        });\n      });\n    });\n\n    describe('destroy', () => {\n      beforeEach(() => {\n        passedElement = document.createElement('input');\n        passedElement.type = 'text';\n        passedElement.className = 'js-choices';\n        document.body.appendChild(passedElement);\n\n        instance = new Choices(passedElement, { allowHTML: true });\n      });\n\n      describe('not already initialised', () => {\n        beforeEach(() => {\n          instance.initialised = false;\n          instance.initialisedOK = undefined;\n          instance.destroy();\n        });\n\n        it(\"doesn't set initialise flag\", () => {\n          expect(instance.initialised).to.not.equal(true);\n        });\n      });\n\n      describe('when already initialised', () => {\n        let removeEventListenersSpy;\n        let passedElementRevealSpy;\n        let containerOuterUnwrapSpy;\n        let clearStoreSpy;\n\n        beforeEach(() => {\n          removeEventListenersSpy = spy(instance, '_removeEventListeners');\n          passedElementRevealSpy = spy(instance.passedElement, 'reveal');\n          containerOuterUnwrapSpy = spy(instance.containerOuter, 'unwrap');\n          clearStoreSpy = spy(instance, 'clearStore');\n\n          instance.initialised = true;\n          instance.destroy();\n        });\n\n        afterEach(() => {\n          removeEventListenersSpy.restore();\n          passedElementRevealSpy.restore();\n          containerOuterUnwrapSpy.restore();\n          clearStoreSpy.restore();\n        });\n\n        it('removes event listeners', () => {\n          expect(removeEventListenersSpy.called).to.equal(true);\n        });\n\n        it('reveals passed element', () => {\n          expect(passedElementRevealSpy.called).to.equal(true);\n        });\n\n        it('reverts outer container', () => {\n          expect(containerOuterUnwrapSpy.called).to.equal(true);\n          expect(containerOuterUnwrapSpy.lastCall.args[0]).to.equal(instance.passedElement.element);\n        });\n\n        it('clears store', () => {\n          expect(clearStoreSpy.called).to.equal(true);\n        });\n\n        it('restes templates config', () => {\n          expect(instance._templates).to.deep.equal(templates);\n        });\n\n        it('resets initialise flag', () => {\n          expect(instance.initialised).to.equal(false);\n        });\n      });\n    });\n\n    describe('enable', () => {\n      let passedElementEnableSpy;\n      let addEventListenersSpy;\n      let containerOuterEnableSpy;\n      let inputEnableSpy;\n\n      beforeEach(() => {\n        addEventListenersSpy = spy(instance, '_addEventListeners');\n        passedElementEnableSpy = spy(instance.passedElement, 'enable');\n        containerOuterEnableSpy = spy(instance.containerOuter, 'enable');\n        inputEnableSpy = spy(instance.input, 'enable');\n      });\n\n      afterEach(() => {\n        addEventListenersSpy.restore();\n        passedElementEnableSpy.restore();\n        containerOuterEnableSpy.restore();\n        inputEnableSpy.restore();\n      });\n\n      describe('when already enabled', () => {\n        beforeEach(() => {\n          instance.passedElement.isDisabled = false;\n          instance.containerOuter.isDisabled = false;\n          output = instance.enable();\n        });\n\n        it('returns this', () => {\n          expect(output).to.deep.equal(instance);\n        });\n\n        it('returns early', () => {\n          expect(passedElementEnableSpy.called).to.equal(false);\n          expect(addEventListenersSpy.called).to.equal(false);\n          expect(inputEnableSpy.called).to.equal(false);\n          expect(containerOuterEnableSpy.called).to.equal(false);\n        });\n      });\n\n      describe('when not already enabled', () => {\n        beforeEach(() => {\n          instance.passedElement.isDisabled = true;\n          instance.containerOuter.isDisabled = true;\n          instance.enable();\n        });\n\n        it('adds event listeners', () => {\n          expect(addEventListenersSpy.called).to.equal(true);\n        });\n\n        it('enables input', () => {\n          expect(inputEnableSpy.called).to.equal(true);\n        });\n\n        it('enables containerOuter', () => {\n          expect(containerOuterEnableSpy.called).to.equal(true);\n        });\n      });\n    });\n\n    describe('disable', () => {\n      let removeEventListenersSpy;\n      let passedElementDisableSpy;\n      let containerOuterDisableSpy;\n      let inputDisableSpy;\n\n      beforeEach(() => {\n        removeEventListenersSpy = spy(instance, '_removeEventListeners');\n        passedElementDisableSpy = spy(instance.passedElement, 'disable');\n        containerOuterDisableSpy = spy(instance.containerOuter, 'disable');\n        inputDisableSpy = spy(instance.input, 'disable');\n      });\n\n      afterEach(() => {\n        removeEventListenersSpy.restore();\n        passedElementDisableSpy.restore();\n        containerOuterDisableSpy.restore();\n        inputDisableSpy.restore();\n      });\n\n      describe('when already disabled', () => {\n        beforeEach(() => {\n          instance.passedElement.isDisabled = true;\n          instance.containerOuter.isDisabled = true;\n          output = instance.disable();\n        });\n\n        it('returns this', () => {\n          expect(output).to.deep.equal(instance);\n        });\n\n        it('returns early', () => {\n          expect(removeEventListenersSpy.called).to.equal(false);\n          expect(passedElementDisableSpy.called).to.equal(false);\n          expect(containerOuterDisableSpy.called).to.equal(false);\n          expect(inputDisableSpy.called).to.equal(false);\n        });\n      });\n\n      describe('when not already disabled', () => {\n        beforeEach(() => {\n          instance.passedElement.isDisabled = false;\n          instance.containerOuter.isDisabled = false;\n          output = instance.disable();\n        });\n\n        it('removes event listeners', () => {\n          expect(removeEventListenersSpy.called).to.equal(true);\n        });\n\n        it('disables input', () => {\n          expect(inputDisableSpy.called).to.equal(true);\n        });\n\n        it('enables containerOuter', () => {\n          expect(containerOuterDisableSpy.called).to.equal(true);\n        });\n      });\n    });\n\n    describe('showDropdown', () => {\n      let containerOuterOpenSpy;\n      let dropdownShowSpy;\n      let inputFocusSpy;\n      let passedElementTriggerEventStub;\n\n      beforeEach(() => {\n        containerOuterOpenSpy = spy(instance.containerOuter, 'open');\n        dropdownShowSpy = spy(instance.dropdown, 'show');\n        inputFocusSpy = spy(instance.input, 'focus');\n        passedElementTriggerEventStub = stub();\n\n        instance.passedElement.triggerEvent = passedElementTriggerEventStub;\n      });\n\n      afterEach(() => {\n        containerOuterOpenSpy.restore();\n        dropdownShowSpy.restore();\n        inputFocusSpy.restore();\n        instance.passedElement.triggerEvent.reset();\n      });\n\n      describe('dropdown active', () => {\n        beforeEach(() => {\n          instance.dropdown.isActive = true;\n          output = instance.showDropdown();\n        });\n\n        it('returns this', () => {\n          expect(output).to.deep.equal(instance);\n        });\n\n        it('returns early', () => {\n          expect(containerOuterOpenSpy.called).to.equal(false);\n          expect(dropdownShowSpy.called).to.equal(false);\n          expect(inputFocusSpy.called).to.equal(false);\n          expect(passedElementTriggerEventStub.called).to.equal(false);\n        });\n      });\n\n      describe('dropdown inactive', () => {\n        beforeEach(() => {\n          instance.dropdown.isActive = false;\n          output = instance.showDropdown();\n        });\n\n        it('returns this', () => {\n          expect(output).to.deep.equal(instance);\n        });\n\n        it('opens containerOuter', () =>\n          new Promise((done) => {\n            requestAnimationFrame(() => {\n              expect(containerOuterOpenSpy.called).to.equal(true);\n              done(true);\n            });\n          }));\n\n        it('shows dropdown with blurInput flag', () =>\n          new Promise((done) => {\n            requestAnimationFrame(() => {\n              expect(dropdownShowSpy.called).to.equal(true);\n              done(true);\n            });\n          }));\n\n        it('triggers event on passedElement', () =>\n          new Promise((done) => {\n            requestAnimationFrame(() => {\n              expect(passedElementTriggerEventStub.called).to.equal(true);\n              expect(passedElementTriggerEventStub.lastCall.args[0]).to.deep.equal(EventType.showDropdown);\n              expect(passedElementTriggerEventStub.lastCall.args[1]).to.undefined;\n              done(true);\n            });\n          }));\n\n        describe('passing true focusInput flag with canSearch set to true', () => {\n          beforeEach(() => {\n            instance.dropdown.isActive = false;\n            instance._canSearch = true;\n            output = instance.showDropdown(true);\n          });\n\n          it('focuses input', () =>\n            new Promise((done) => {\n              requestAnimationFrame(() => {\n                expect(inputFocusSpy.called).to.equal(false);\n                done(true);\n              });\n            }));\n        });\n      });\n    });\n\n    describe('hideDropdown', () => {\n      let containerOuterCloseSpy;\n      let dropdownHideSpy;\n      let inputBlurSpy;\n      let inputRemoveActiveDescendantSpy;\n      let passedElementTriggerEventStub;\n\n      beforeEach(() => {\n        containerOuterCloseSpy = spy(instance.containerOuter, 'close');\n        dropdownHideSpy = spy(instance.dropdown, 'hide');\n        inputBlurSpy = spy(instance.input, 'blur');\n        inputRemoveActiveDescendantSpy = spy(instance.input, 'removeActiveDescendant');\n        passedElementTriggerEventStub = stub();\n\n        instance.passedElement.triggerEvent = passedElementTriggerEventStub;\n      });\n\n      afterEach(() => {\n        containerOuterCloseSpy.restore();\n        dropdownHideSpy.restore();\n        inputBlurSpy.restore();\n        inputRemoveActiveDescendantSpy.restore();\n        instance.passedElement.triggerEvent.reset();\n      });\n\n      describe('dropdown inactive', () => {\n        beforeEach(() => {\n          instance.dropdown.isActive = false;\n          output = instance.hideDropdown();\n        });\n\n        it('returns this', () => {\n          expect(output).to.deep.equal(instance);\n        });\n\n        it('returns early', () => {\n          expect(containerOuterCloseSpy.called).to.equal(false);\n          expect(dropdownHideSpy.called).to.equal(false);\n          expect(inputBlurSpy.called).to.equal(false);\n          expect(passedElementTriggerEventStub.called).to.equal(false);\n        });\n      });\n\n      describe('dropdown active', () => {\n        beforeEach(() => {\n          instance.dropdown.isActive = true;\n          output = instance.hideDropdown();\n        });\n\n        it('returns this', () => {\n          expect(output).to.deep.equal(instance);\n        });\n\n        it('closes containerOuter', () =>\n          new Promise((done) => {\n            requestAnimationFrame(() => {\n              expect(containerOuterCloseSpy.called).to.equal(true);\n              done(true);\n            });\n          }));\n\n        it('hides dropdown with blurInput flag', () =>\n          new Promise((done) => {\n            requestAnimationFrame(() => {\n              expect(dropdownHideSpy.called).to.equal(true);\n              done(true);\n            });\n          }));\n\n        it('triggers event on passedElement', () =>\n          new Promise((done) => {\n            requestAnimationFrame(() => {\n              expect(passedElementTriggerEventStub.called).to.equal(true);\n              expect(passedElementTriggerEventStub.lastCall.args[0]).to.deep.equal(EventType.hideDropdown);\n              expect(passedElementTriggerEventStub.lastCall.args[1]).to.undefined;\n              done(true);\n            });\n          }));\n\n        describe('passing true blurInput flag with canSearch set to true', () => {\n          beforeEach(() => {\n            instance.dropdown.isActive = true;\n            instance._canSearch = true;\n            output = instance.hideDropdown(true);\n          });\n\n          it('removes active descendants', () =>\n            new Promise((done) => {\n              requestAnimationFrame(() => {\n                expect(inputRemoveActiveDescendantSpy.called).to.equal(true);\n                done(true);\n              });\n            }));\n\n          it('blurs input', () =>\n            new Promise((done) => {\n              requestAnimationFrame(() => {\n                expect(inputBlurSpy.called).to.equal(true);\n                done(true);\n              });\n            }));\n        });\n      });\n    });\n\n    describe('highlightItem', () => {\n      let passedElementTriggerEventStub;\n      let storeDispatchSpy;\n      let storeGetGroupByIdStub;\n      let choicesStub;\n      let itemsStub;\n      const groupIdValue = 'Test';\n      const item: ChoiceFull = {\n        group: null,\n        highlighted: false,\n        active: false,\n        disabled: false,\n        placeholder: false,\n        selected: false,\n        id: 1234,\n        value: 'Test',\n        label: 'Test',\n        score: 0,\n        rank: 0,\n      };\n\n      beforeEach(() => {\n        choicesStub = stub(instance._store, 'choices').get(() => [item]);\n        itemsStub = stub(instance._store, 'items').get(() => [item]);\n        passedElementTriggerEventStub = stub();\n        storeGetGroupByIdStub = stub().returns({\n          id: 4321,\n          label: groupIdValue,\n        });\n        storeDispatchSpy = spy(instance._store, 'dispatch');\n\n        instance._store.getGroupById = storeGetGroupByIdStub;\n        instance.passedElement.triggerEvent = passedElementTriggerEventStub;\n      });\n\n      afterEach(() => {\n        choicesStub.reset();\n        itemsStub.reset();\n        storeDispatchSpy.restore();\n        instance._store.getGroupById.reset();\n        instance.passedElement.triggerEvent.reset();\n      });\n\n      describe('no item passed', () => {\n        beforeEach(() => {\n          output = instance.highlightItem();\n        });\n\n        it('returns this', () => {\n          expect(output).to.deep.equal(instance);\n        });\n\n        it('returns early', () => {\n          expect(passedElementTriggerEventStub.called).to.equal(false);\n          expect(storeDispatchSpy.called).to.equal(false);\n          expect(storeGetGroupByIdStub.called).to.equal(false);\n        });\n      });\n\n      describe('item passed', () => {\n        describe('passing truthy second paremeter', () => {\n          beforeEach(() => {\n            output = instance.highlightItem(item, true);\n          });\n\n          it('returns this', () => {\n            expect(output).to.deep.equal(instance);\n          });\n\n          it('dispatches highlightItem action with correct arguments', () => {\n            expect(storeDispatchSpy.called).to.equal(true);\n            expect(storeDispatchSpy.lastCall.args[0]).to.deep.equal({\n              type: ActionType.HIGHLIGHT_ITEM,\n              item,\n              highlighted: true,\n            });\n          });\n        });\n\n        describe('item with no group', () => {\n          beforeEach(() => {\n            item.group = null;\n            output = instance.highlightItem(item);\n          });\n\n          it('triggers event with null groupValue', () => {\n            expect(passedElementTriggerEventStub.called).to.equal(true);\n            expect(passedElementTriggerEventStub.lastCall.args[0]).to.equal(EventType.highlightItem);\n            expect(passedElementTriggerEventStub.lastCall.args[1]).to.contains({\n              id: item.id,\n              value: item.value,\n              label: item.label,\n              groupValue: undefined,\n            });\n          });\n        });\n\n        describe('item with group', () => {\n          beforeEach(() => {\n            item.group = {\n              active: true,\n              choices: [],\n              disabled: false,\n              element: undefined,\n              groupEl: undefined,\n              id: 4321,\n              label: groupIdValue,\n            };\n            output = instance.highlightItem(item);\n          });\n\n          it('triggers event with groupValue', () => {\n            expect(passedElementTriggerEventStub.called).to.equal(true);\n            expect(passedElementTriggerEventStub.lastCall.args[0]).to.equal(EventType.highlightItem);\n            expect(passedElementTriggerEventStub.lastCall.args[1]).to.contains({\n              id: item.id,\n              value: item.value,\n              label: item.label,\n              groupValue: groupIdValue,\n            });\n          });\n        });\n\n        describe('passing falsey second paremeter', () => {\n          beforeEach(() => {\n            output = instance.highlightItem(item, false);\n          });\n\n          it(\"doesn't trigger event\", () => {\n            expect(passedElementTriggerEventStub.called).to.equal(false);\n          });\n\n          it('returns this', () => {\n            expect(output).to.deep.equal(instance);\n          });\n        });\n      });\n    });\n\n    describe('unhighlightItem', () => {\n      let choicesStub;\n      let itemsStub;\n      let passedElementTriggerEventStub;\n      let storeDispatchSpy;\n      let storeGetGroupByIdStub;\n      const groupIdValue = 'Test';\n      const item: ChoiceFull = {\n        group: null,\n        highlighted: true,\n        active: false,\n        disabled: false,\n        placeholder: false,\n        selected: false,\n        id: 1234,\n        value: 'Test',\n        label: 'Test',\n        score: 0,\n        rank: 0,\n      };\n\n      beforeEach(() => {\n        choicesStub = stub(instance._store, 'choices').get(() => [item]);\n        itemsStub = stub(instance._store, 'items').get(() => [item]);\n        passedElementTriggerEventStub = stub();\n        storeGetGroupByIdStub = stub().returns({\n          id: 4321,\n          label: groupIdValue,\n        });\n        storeDispatchSpy = spy(instance._store, 'dispatch');\n\n        instance._store.getGroupById = storeGetGroupByIdStub;\n        instance.passedElement.triggerEvent = passedElementTriggerEventStub;\n      });\n\n      afterEach(() => {\n        choicesStub.reset();\n        itemsStub.reset();\n        storeDispatchSpy.restore();\n        instance._store.getGroupById.reset();\n        instance.passedElement.triggerEvent.reset();\n      });\n\n      describe('no item passed', () => {\n        beforeEach(() => {\n          output = instance.unhighlightItem();\n        });\n\n        it('returns this', () => {\n          expect(output).to.deep.equal(instance);\n        });\n\n        it('returns early', () => {\n          expect(passedElementTriggerEventStub.called).to.equal(false);\n          expect(storeDispatchSpy.called).to.equal(false);\n          expect(storeGetGroupByIdStub.called).to.equal(false);\n        });\n      });\n\n      describe('item passed', () => {\n        describe('passing truthy second paremeter', () => {\n          beforeEach(() => {\n            output = instance.unhighlightItem(item, true);\n          });\n\n          it('returns this', () => {\n            expect(output).to.deep.equal(instance);\n          });\n\n          it('dispatches highlightItem action with correct arguments', () => {\n            expect(storeDispatchSpy.called).to.equal(true);\n            expect(storeDispatchSpy.lastCall.args[0]).to.deep.contains({\n              type: ActionType.HIGHLIGHT_ITEM,\n              item,\n              highlighted: false,\n            });\n          });\n        });\n\n        describe('item without group', () => {\n          beforeEach(() => {\n            item.group = null;\n            output = instance.unhighlightItem(item);\n          });\n\n          it('triggers event with null groupValue', () => {\n            expect(passedElementTriggerEventStub.called).to.equal(true);\n            expect(passedElementTriggerEventStub.lastCall.args[0]).to.equal(EventType.unhighlightItem);\n            expect(passedElementTriggerEventStub.lastCall.args[1]).to.contains({\n              value: item.value,\n              label: item.label,\n              groupValue: undefined,\n            });\n          });\n        });\n\n        describe('item with group', () => {\n          beforeEach(() => {\n            item.group = {\n              active: true,\n              choices: [],\n              disabled: false,\n              element: undefined,\n              groupEl: undefined,\n              id: 4321,\n              label: groupIdValue,\n            };\n            output = instance.unhighlightItem(item);\n          });\n\n          it('triggers event with groupValue', () => {\n            expect(passedElementTriggerEventStub.called).to.equal(true);\n            expect(passedElementTriggerEventStub.lastCall.args[0]).to.equal(EventType.unhighlightItem);\n            expect(passedElementTriggerEventStub.lastCall.args[1]).to.contains({\n              value: item.value,\n              label: item.label,\n              groupValue: groupIdValue,\n            });\n          });\n        });\n\n        describe('passing falsey second paremeter', () => {\n          beforeEach(() => {\n            output = instance.unhighlightItem(item, false);\n          });\n\n          it(\"doesn't trigger event\", () => {\n            expect(passedElementTriggerEventStub.called).to.equal(false);\n          });\n\n          it('returns this', () => {\n            expect(output).to.deep.equal(instance);\n          });\n        });\n      });\n    });\n\n    describe('highlightAll', () => {\n      let choicesStub;\n      let itemsStub;\n      let storeDispatchSpy;\n\n      const items: ChoiceFull[] = [\n        {\n          id: 1,\n          value: 'Test 1',\n          highlighted: false,\n          disabled: false,\n          active: false,\n          group: null,\n          label: '',\n          placeholder: false,\n          selected: false,\n          score: 0,\n          rank: 0,\n        },\n        {\n          id: 2,\n          value: 'Test 2',\n          highlighted: false,\n          disabled: false,\n          active: false,\n          group: null,\n          label: '',\n          placeholder: false,\n          selected: false,\n          score: 0,\n          rank: 0,\n        },\n      ];\n\n      beforeEach(() => {\n        choicesStub = stub(instance._store, 'choices').get(() => items);\n        itemsStub = stub(instance._store, 'items').get(() => items);\n        storeDispatchSpy = spy(instance._store, 'dispatch');\n\n        output = instance.highlightAll();\n      });\n\n      afterEach(() => {\n        storeDispatchSpy.restore();\n        choicesStub.reset();\n        itemsStub.reset();\n      });\n\n      it('returns this', () => {\n        expect(output).to.deep.equal(instance);\n      });\n\n      it('highlights each item in store', () => {\n        expect(storeDispatchSpy.callCount).to.equal(items.length);\n        expect(storeDispatchSpy.firstCall.args[0]).to.deep.contains({\n          type: ActionType.HIGHLIGHT_ITEM,\n          item: items[0],\n          highlighted: true,\n        });\n        expect(storeDispatchSpy.lastCall.args[0]).to.deep.contains({\n          type: ActionType.HIGHLIGHT_ITEM,\n          item: items[1],\n          highlighted: true,\n        });\n      });\n    });\n\n    describe('unhighlightAll', () => {\n      let choicesStub;\n      let itemsStub;\n      let storeDispatchSpy;\n\n      const items: ChoiceFull[] = [\n        {\n          id: 1,\n          value: 'Test 1',\n          highlighted: true,\n          disabled: false,\n          active: false,\n          group: null,\n          label: '',\n          placeholder: false,\n          selected: false,\n          score: 0,\n          rank: 0,\n        },\n        {\n          id: 2,\n          value: 'Test 2',\n          highlighted: true,\n          disabled: false,\n          active: false,\n          group: null,\n          label: '',\n          placeholder: false,\n          selected: false,\n          score: 0,\n          rank: 0,\n        },\n      ];\n\n      beforeEach(() => {\n        choicesStub = stub(instance._store, 'choices').get(() => items);\n        itemsStub = stub(instance._store, 'items').get(() => items);\n        storeDispatchSpy = spy(instance._store, 'dispatch');\n\n        output = instance.unhighlightAll();\n      });\n\n      afterEach(() => {\n        storeDispatchSpy.restore();\n        choicesStub.reset();\n        itemsStub.reset();\n      });\n\n      it('returns this', () => {\n        expect(output).to.deep.equal(instance);\n      });\n\n      it('unhighlights each item in store', () => {\n        expect(storeDispatchSpy.callCount).to.equal(items.length);\n        expect(storeDispatchSpy.firstCall.args[0]).to.deep.contains({\n          type: ActionType.HIGHLIGHT_ITEM,\n          item: items[0],\n          highlighted: false,\n        });\n        expect(storeDispatchSpy.lastCall.args[0]).to.deep.contains({\n          type: ActionType.HIGHLIGHT_ITEM,\n          item: items[1],\n          highlighted: false,\n        });\n      });\n    });\n\n    describe('clearChoices', () => {\n      let storeResetStub;\n\n      beforeEach(() => {\n        storeResetStub = stub();\n        instance._store.reset = storeResetStub;\n\n        output = instance.clearChoices();\n      });\n\n      afterEach(() => {\n        instance._store.reset.reset();\n      });\n\n      it('returns this', () => {\n        expect(output).to.deep.equal(instance);\n      });\n\n      it('dispatches clearChoices action', () => {\n        expect(storeResetStub.callCount).to.be.eq(1);\n      });\n    });\n\n    describe('clearInput', () => {\n      let inputClearSpy;\n      let storeDispatchStub;\n\n      beforeEach(() => {\n        inputClearSpy = spy(instance.input, 'clear');\n        storeDispatchStub = stub();\n        instance._store.dispatch = storeDispatchStub;\n        output = instance.clearInput();\n      });\n\n      afterEach(() => {\n        inputClearSpy.restore();\n        instance._store.dispatch.reset();\n      });\n\n      it('returns this', () => {\n        expect(output).to.deep.equal(instance);\n      });\n\n      describe('text element', () => {\n        beforeEach(() => {\n          instance._isSelectOneElement = false;\n          instance._isTextElement = false;\n\n          output = instance.clearInput();\n        });\n\n        it('clears input with correct arguments', () => {\n          expect(inputClearSpy.called).to.equal(true);\n          expect(inputClearSpy.lastCall.args[0]).to.equal(true);\n        });\n      });\n\n      describe('select element with search enabled', () => {\n        beforeEach(() => {\n          instance._isSelectOneElement = true;\n          instance._isTextElement = false;\n          instance.config.searchEnabled = true;\n          instance._isSearching = true;\n\n          output = instance.clearInput();\n        });\n\n        it('clears input with correct arguments', () => {\n          expect(inputClearSpy.called).to.equal(true);\n          expect(inputClearSpy.lastCall.args[0]).to.equal(false);\n        });\n\n        it('resets search flag', () => {\n          expect(instance._isSearching).to.equal(false);\n        });\n\n        it('dispatches activateChoices action', () => {\n          expect(storeDispatchStub.called).to.equal(true);\n          expect(storeDispatchStub.lastCall.args[0]).to.deep.equal({\n            type: ActionType.ACTIVATE_CHOICES,\n            active: true,\n          });\n        });\n      });\n    });\n\n    describe('setChoices with callback/Promise', () => {\n      describe('not initialised', () => {\n        beforeEach(() => {\n          instance.initialised = false;\n          instance.initialisedOK = undefined;\n        });\n\n        it('should throw', () => {\n          expect(() => instance.setChoices(null)).Throw(TypeError);\n        });\n      });\n\n      describe('initialised twice', () => {\n        it('throws', () => {\n          instance.initialised = true;\n          instance.initialisedOK = false;\n          expect(() => instance.setChoices(null)).to.throw(\n            TypeError,\n            'setChoices called for an element which has multiple instances of Choices initialised on it',\n          );\n        });\n      });\n\n      describe('text element', () => {\n        beforeEach(() => {\n          instance._isSelectElement = false;\n        });\n\n        it('should throw', () => {\n          expect(() => instance.setChoices(null)).Throw(TypeError);\n        });\n      });\n\n      describe('passing invalid function', () => {\n        beforeEach(() => {\n          instance._isSelectElement = true;\n        });\n\n        it('should throw on non function', () => {\n          expect(() => instance.setChoices(null)).Throw(TypeError, /Promise/i);\n        });\n\n        it(`should throw on function that doesn't return promise`, () => {\n          expect(() => instance.setChoices(() => 'boo')).to.throw(TypeError, /promise/i);\n        });\n      });\n\n      describe('select element', () => {\n        it('fetches and sets choices', async () => {\n          document.body.innerHTML = '<select id=\"test\" />';\n          const choice = new Choices('#test', { allowHTML: true });\n          const handleLoadingStateSpy = spy(choice, '_handleLoadingState');\n\n          let fetcherCalled = false;\n          const fetcher = async (inst): Promise<InputChoice[]> => {\n            expect(inst).to.eq(choice);\n            fetcherCalled = true;\n            // eslint-disable-next-line no-promise-executor-return\n            await new Promise((resolve) => setTimeout(resolve, 800));\n\n            return [\n              { label: 'l1', value: 'v1', customProperties: { prop1: true } },\n              { label: 'l2', value: 'v2', customProperties: { prop2: false } },\n            ];\n          };\n          expect(choice._store.choices.length).to.equal(0);\n          const promise = choice.setChoices(fetcher);\n          expect(fetcherCalled).to.be.true;\n          const res = await promise;\n          expect(res).to.equal(choice);\n          expect(handleLoadingStateSpy.callCount).to.equal(2);\n          expect(choice._store.choices[1].value).to.equal('v2');\n          expect(choice._store.choices[1].label).to.equal('l2');\n          expect(choice._store.choices[1].customProperties).to.deep.equal({\n            prop2: false,\n          });\n        });\n      });\n    });\n\n    describe('setValue', () => {\n      let _addChoiceStub;\n      const value1 = 'Value 1';\n      const value2 = {\n        value: 'Value 2',\n      };\n      const values = [value1, value2];\n\n      beforeEach(() => {\n        _addChoiceStub = stub();\n        instance._addChoice = _addChoiceStub;\n      });\n\n      afterEach(() => {\n        instance._addChoice.reset();\n      });\n\n      describe('not already initialised', () => {\n        it('throws', () => {\n          instance.initialised = false;\n          instance.initialisedOK = undefined;\n          expect(() => instance.setValue(values)).to.throw(\n            TypeError,\n            'setValue called on a non-initialised instance of Choices',\n          );\n        });\n      });\n\n      describe('initialised twice', () => {\n        it('throws', () => {\n          instance.initialised = true;\n          instance.initialisedOK = false;\n          expect(() => instance.setValue(values)).to.throw(\n            TypeError,\n            'setValue called for an element which has multiple instances of Choices initialised on it',\n          );\n        });\n      });\n\n      describe('when already initialised', () => {\n        beforeEach(() => {\n          instance.initialised = true;\n          output = instance.setValue(values);\n        });\n\n        it('returns this', () => {\n          expect(output).to.deep.equal(instance);\n        });\n\n        it('sets each value', () => {\n          expect(_addChoiceStub.callCount).to.equal(2);\n          expect(_addChoiceStub.firstCall.args[0]).to.be.a('object');\n          expect(_addChoiceStub.secondCall.args[0]).to.be.a('object');\n          expect(value1).to.equal(_addChoiceStub.firstCall.args[0].value);\n          expect(value2.value).to.equal(_addChoiceStub.secondCall.args[0].value);\n        });\n      });\n    });\n\n    describe('setChoiceByValue', () => {\n      let findAndSelectChoiceByValueStub;\n\n      beforeEach(() => {\n        findAndSelectChoiceByValueStub = stub();\n        instance._findAndSelectChoiceByValue = findAndSelectChoiceByValueStub;\n      });\n\n      afterEach(() => {\n        instance._findAndSelectChoiceByValue.reset();\n      });\n\n      describe('not already initialised', () => {\n        it('throws', () => {\n          instance.initialised = false;\n          instance.initialisedOK = undefined;\n          expect(() => instance.setChoiceByValue([])).to.throw(\n            TypeError,\n            'setChoiceByValue called on a non-initialised instance of Choices',\n          );\n        });\n      });\n\n      describe('initialised twice', () => {\n        it('throws', () => {\n          instance.initialised = true;\n          instance.initialisedOK = false;\n          expect(() => instance.setChoiceByValue([])).to.throw(\n            TypeError,\n            'setChoiceByValue called for an element which has multiple instances of Choices initialised on it',\n          );\n        });\n      });\n\n      describe('when already initialised and not text element', () => {\n        beforeEach(() => {\n          instance.initialised = true;\n          instance._isTextElement = false;\n        });\n\n        describe('passing a string value', () => {\n          const value = 'Test value';\n\n          beforeEach(() => {\n            output = instance.setChoiceByValue(value);\n          });\n\n          it('returns this', () => {\n            expect(output).to.deep.equal(instance);\n          });\n\n          it('sets each choice with same value', () => {\n            expect(findAndSelectChoiceByValueStub.called).to.equal(true);\n            expect(findAndSelectChoiceByValueStub.firstCall.args[0]).to.equal(value);\n          });\n        });\n\n        describe('passing an array of values', () => {\n          const values = ['Value 1', 'Value 2'];\n\n          beforeEach(() => {\n            output = instance.setChoiceByValue(values);\n          });\n\n          it('returns this', () => {\n            expect(output).to.deep.equal(instance);\n          });\n\n          it('sets each choice with same value', () => {\n            expect(findAndSelectChoiceByValueStub.callCount).to.equal(2);\n            expect(findAndSelectChoiceByValueStub.firstCall.args[0]).to.equal(values[0]);\n            expect(findAndSelectChoiceByValueStub.secondCall.args[0]).to.equal(values[1]);\n          });\n        });\n      });\n    });\n\n    describe('getValue', () => {\n      let activeItemsStub;\n      const items = [\n        {\n          id: '1',\n          value: 'Test value 1',\n        },\n        {\n          id: '2',\n          value: 'Test value 2',\n        },\n      ];\n\n      beforeEach(() => {\n        activeItemsStub = stub(instance._store, 'items').get(() => items);\n      });\n\n      afterEach(() => {\n        activeItemsStub.reset();\n      });\n\n      describe('passing true valueOnly flag', () => {\n        describe('select one input', () => {\n          beforeEach(() => {\n            instance._isSelectOneElement = true;\n            output = instance.getValue(true);\n          });\n\n          it('returns a single action value', () => {\n            expect(output).to.equal(items[0].value);\n          });\n        });\n\n        describe('non select one input', () => {\n          beforeEach(() => {\n            instance._isSelectOneElement = false;\n            output = instance.getValue(true);\n          });\n\n          it('returns all active item values', () => {\n            expect(output).to.deep.equal(items.map((item) => item.value));\n          });\n        });\n      });\n\n      describe('passing false valueOnly flag', () => {\n        describe('select one input', () => {\n          beforeEach(() => {\n            instance._isSelectOneElement = true;\n            output = instance.getValue(false);\n          });\n\n          it('returns a single active item', () => {\n            expect(output).to.contain.keys(Object.keys(items[0]));\n          });\n        });\n\n        describe('non select one input', () => {\n          beforeEach(() => {\n            instance._isSelectOneElement = false;\n            output = instance.getValue(false);\n          });\n\n          it('returns all active items', () => {\n            output.forEach((choice) => {\n              expect(choice).to.contain.keys(Object.keys(items[0])).all;\n            });\n          });\n        });\n      });\n    });\n\n    describe('removeActiveItemsByValue', () => {\n      let activeItemsStub;\n      let removeItemStub;\n      const value = 'Removed';\n      const items = [\n        {\n          id: '1',\n          value: 'Not removed',\n        },\n        {\n          id: '2',\n          value: 'Removed',\n        },\n        {\n          id: '3',\n          value: 'Removed',\n        },\n      ];\n\n      beforeEach(() => {\n        removeItemStub = stub();\n        activeItemsStub = stub(instance._store, 'items').get(() => items);\n        instance._removeItem = removeItemStub;\n\n        output = instance.removeActiveItemsByValue(value);\n      });\n\n      afterEach(() => {\n        activeItemsStub.reset();\n        instance._removeItem.reset();\n      });\n\n      it('removes each active item in store with matching value', () => {\n        expect(removeItemStub.callCount).to.equal(2);\n        expect(removeItemStub.firstCall.args[0]).to.equal(items[1]);\n        expect(removeItemStub.secondCall.args[0]).to.equal(items[2]);\n      });\n    });\n\n    describe('removeActiveItems', () => {\n      let activeItemsStub;\n      let removeItemStub;\n      const items = [\n        {\n          id: '1',\n          value: 'Not removed',\n        },\n        {\n          id: '2',\n          value: 'Removed',\n        },\n        {\n          id: '3',\n          value: 'Removed',\n        },\n      ];\n\n      beforeEach(() => {\n        removeItemStub = stub();\n        activeItemsStub = stub(instance._store, 'items').get(() => items);\n        instance._removeItem = removeItemStub;\n      });\n\n      afterEach(() => {\n        activeItemsStub.reset();\n        instance._removeItem.reset();\n      });\n\n      describe('not passing id to exclude', () => {\n        beforeEach(() => {\n          output = instance.removeActiveItems();\n        });\n\n        it('removes all active items in store', () => {\n          expect(removeItemStub.callCount).to.equal(items.length);\n          expect(removeItemStub.firstCall.args[0]).to.equal(items[0]);\n          expect(removeItemStub.secondCall.args[0]).to.equal(items[1]);\n          expect(removeItemStub.thirdCall.args[0]).to.equal(items[2]);\n        });\n      });\n\n      describe('passing id to exclude', () => {\n        const idToExclude = '2';\n\n        beforeEach(() => {\n          output = instance.removeActiveItems(idToExclude);\n        });\n\n        it('removes all active items in store with id that does match excludedId', () => {\n          expect(removeItemStub.callCount).to.equal(2);\n          expect(removeItemStub.firstCall.args[0]).to.equal(items[0]);\n          expect(removeItemStub.secondCall.args[0]).to.equal(items[2]);\n        });\n      });\n    });\n\n    describe('removeChoice', () => {\n      let choicesStub;\n      let itemsStub;\n      let dispatchStub;\n      let triggerEventStub;\n\n      const items = [\n        {\n          id: 1,\n          value: 'Test 1',\n          selected: true,\n        },\n        {\n          id: 2,\n          value: 'Test 2',\n          selected: false,\n        },\n      ];\n\n      beforeEach(() => {\n        choicesStub = stub(instance._store, 'choices').get(() => items);\n        itemsStub = stub(instance._store, 'items').get(() => items);\n        triggerEventStub = stub();\n        dispatchStub = stub();\n\n        instance._store.dispatch = dispatchStub;\n        instance.passedElement.triggerEvent = triggerEventStub;\n      });\n\n      afterEach(() => {\n        choicesStub.reset();\n        itemsStub.reset();\n        instance._store.dispatch.reset();\n        instance.passedElement.triggerEvent.reset();\n      });\n\n      describe('remove a selected choice from the store', () => {\n        beforeEach(() => {\n          output = instance.removeChoice('Test 1');\n        });\n\n        it('returns this', () => {\n          expect(output).to.deep.equal(instance);\n        });\n\n        it('removes an active item in store', () => {\n          expect(instance._store.dispatch).callCount(1);\n          expect(instance.passedElement.triggerEvent).callCount(1);\n        });\n      });\n\n      describe('remove a non-selected choice from the store', () => {\n        beforeEach(() => {\n          output = instance.removeChoice('Test 2');\n        });\n\n        it('returns this', () => {\n          expect(output).to.deep.equal(instance);\n        });\n\n        it('removes a choice in store', () => {\n          expect(instance._store.dispatch).callCount(1);\n          expect(instance.passedElement.triggerEvent).callCount(0);\n        });\n      });\n\n      describe('remove an non-existent choice from the store', () => {\n        beforeEach(() => {\n          output = instance.removeChoice('xxxx');\n        });\n\n        it('returns this', () => {\n          expect(output).to.deep.equal(instance);\n        });\n\n        it('removes no choices from store', () => {\n          expect(instance._store.dispatch).callCount(0);\n          expect(instance.passedElement.triggerEvent).callCount(0);\n        });\n      });\n    });\n\n    describe('removeHighlightedItems', () => {\n      let highlightedActiveItemsStub;\n      let removeItemStub;\n      let triggerChangeStub;\n\n      const items = [\n        {\n          id: 1,\n          value: 'Test 1',\n        },\n        {\n          id: 2,\n          value: 'Test 2',\n        },\n      ];\n\n      beforeEach(() => {\n        highlightedActiveItemsStub = stub(instance._store, 'highlightedActiveItems').get(() => items);\n        removeItemStub = stub();\n        triggerChangeStub = stub();\n\n        instance._removeItem = removeItemStub;\n        instance._triggerChange = triggerChangeStub;\n      });\n\n      afterEach(() => {\n        highlightedActiveItemsStub.reset();\n        instance._removeItem.reset();\n        instance._triggerChange.reset();\n      });\n\n      describe('runEvent parameter being passed', () => {\n        beforeEach(() => {\n          output = instance.removeHighlightedItems();\n        });\n\n        it('returns this', () => {\n          expect(output).to.deep.equal(instance);\n        });\n\n        it('removes each highlighted item in store', () => {\n          expect(removeItemStub.callCount).to.equal(2);\n        });\n      });\n\n      describe('runEvent parameter not being passed', () => {\n        beforeEach(() => {\n          output = instance.removeHighlightedItems(true);\n        });\n\n        it('returns this', () => {\n          expect(output).to.deep.equal(instance);\n        });\n\n        it('triggers event with item value', () => {\n          expect(triggerChangeStub.callCount).to.equal(2);\n          expect(triggerChangeStub.firstCall.args[0]).to.equal(items[0].value);\n          expect(triggerChangeStub.secondCall.args[0]).to.equal(items[1].value);\n        });\n      });\n    });\n\n    describe('setChoices', () => {\n      let clearChoicesStub;\n      let addGroupStub;\n      let addChoiceStub;\n      let containerOuterRemoveLoadingStateStub;\n      const value = 'value';\n      const label = 'label';\n      const choices: InputChoice[] = [\n        {\n          value: '1',\n          label: 'Test 1',\n          selected: false,\n          disabled: false,\n        },\n        {\n          value: '2',\n          label: 'Test 2',\n          selected: false,\n          disabled: true,\n        },\n      ];\n      const groups: InputGroup[] = [\n        {\n          ...choices[0],\n          choices,\n        },\n        {\n          ...choices[1],\n          choices: [],\n        },\n      ];\n\n      beforeEach(() => {\n        clearChoicesStub = stub();\n        addGroupStub = stub();\n        addChoiceStub = stub();\n        containerOuterRemoveLoadingStateStub = stub();\n\n        instance.clearChoices = clearChoicesStub;\n        instance._addGroup = addGroupStub;\n        instance._addChoice = addChoiceStub;\n        instance.containerOuter.removeLoadingState = containerOuterRemoveLoadingStateStub;\n      });\n\n      afterEach(() => {\n        instance.clearChoices.reset();\n        instance._addGroup.reset();\n        instance._addChoice.reset();\n        instance.containerOuter.removeLoadingState.reset();\n      });\n\n      describe('when element is not select element', () => {\n        beforeEach(() => {\n          instance._isSelectElement = false;\n        });\n\n        it('throws', () => {\n          expect(() => instance.setChoices(choices, value, label, false)).to.throw(TypeError, /input/i);\n        });\n      });\n\n      describe('passing invalid arguments', () => {\n        describe('passing no value', () => {\n          beforeEach(() => {\n            instance._isSelectElement = true;\n          });\n\n          it('throws', () => {\n            expect(() => instance.setChoices(choices, null, 'label', false)).to.throw(TypeError, /value/i);\n          });\n        });\n      });\n\n      describe('passing valid arguments', () => {\n        beforeEach(() => {\n          instance._isSelectElement = true;\n        });\n\n        it('removes loading state', () => {\n          instance.setChoices(choices, value, label, false);\n          expect(containerOuterRemoveLoadingStateStub.called).to.equal(true);\n        });\n\n        describe('passing choices with children choices', () => {\n          it('adds groups', () => {\n            instance.setChoices(groups, value, label, false);\n            expect(addGroupStub.callCount).to.equal(2);\n            expect(addGroupStub.firstCall.args[0]).to.contain({\n              label: groups[0].label,\n            });\n          });\n        });\n\n        const coerceBool = (arg: unknown, defaultValue: boolean = true) =>\n          typeof arg === 'undefined' ? defaultValue : !!arg;\n\n        describe('passing choices without children choices', () => {\n          it('adds passed choices', () => {\n            instance.setChoices(choices, value, label, false);\n            expect(addChoiceStub.callCount).to.equal(2);\n            addChoiceStub.getCalls().forEach((call, index) => {\n              expect(call.args[0]).to.deep.contain({\n                value: choices[index][value],\n                label: choices[index][label],\n                active: coerceBool(choices[index].active),\n                selected: coerceBool(choices[index].selected, false),\n                disabled: coerceBool(choices[index].disabled, false),\n                customProperties: choices[index].customProperties,\n                placeholder: coerceBool(choices[index].placeholder, false),\n              });\n            });\n          });\n        });\n\n        describe('passing an empty array with a true replaceChoices flag', () => {\n          it('choices are cleared', () => {\n            instance._isSelectElement = true;\n            instance.setChoices([], value, label, true);\n            expect(clearChoicesStub.called).to.equal(true);\n          });\n        });\n\n        describe('passing an empty array with a false replaceChoices flag', () => {\n          it('choices stay the same', () => {\n            instance._isSelectElement = true;\n            instance.setChoices([], value, label, false);\n            expect(clearChoicesStub.called).to.equal(false);\n          });\n        });\n\n        describe('passing true replaceChoices flag', () => {\n          it('choices are cleared', () => {\n            instance.setChoices(choices, value, label, true);\n            expect(clearChoicesStub.called).to.equal(true);\n          });\n        });\n\n        describe('passing false replaceChoices flag', () => {\n          it('choices are not cleared', () => {\n            instance.setChoices(choices, value, label, false);\n            expect(clearChoicesStub.called).to.equal(false);\n          });\n        });\n      });\n    });\n  });\n\n  describe('events', () => {\n    describe('search', () => {\n      const choices: InputChoice[] = [\n        {\n          value: '1',\n          label: 'Test 1',\n          selected: false,\n          disabled: false,\n        },\n        {\n          value: '2',\n          label: 'Test 2',\n          selected: false,\n          disabled: false,\n        },\n      ];\n\n      beforeEach(() => {\n        document.body.innerHTML = `\n        <select data-choice multiple></select>\n        `;\n\n        instance = new Choices('[data-choice]', {\n          choices,\n          allowHTML: false,\n          searchEnabled: true,\n        });\n      });\n\n      describe('fuse', () => {\n        beforeEach(() => {\n          process.env.CHOICES_SEARCH_FUSE = 'full';\n          instance._searcher = new SearchByFuse(instance.config);\n        });\n        it('details are passed', () =>\n          new Promise((done) => {\n            const query = 'This is a <search> query & a \"test\" with characters that should not be sanitised.';\n\n            instance.input.value = query;\n            instance.input.focus();\n            instance.passedElement.element.addEventListener(\n              'search',\n              (event) => {\n                expect(event.detail).to.contains({\n                  value: query,\n                  resultCount: 0,\n                });\n                done(true);\n              },\n              { once: true },\n            );\n\n            instance._onKeyUp({ target: null, keyCode: null });\n            instance._onInput({ target: null });\n          }));\n\n        it('uses Fuse options', () =>\n          new Promise((done) => {\n            instance.config.fuseOptions.isCaseSensitive = true;\n            instance.config.fuseOptions.minMatchCharLength = 4;\n            instance._searcher = new SearchByFuse(instance.config);\n\n            instance.input.value = 'test';\n            instance.input.focus();\n            instance.passedElement.element.addEventListener(\n              'search',\n              (event) => {\n                expect(event.detail.resultCount).to.eql(0);\n                done(true);\n              },\n              { once: true },\n            );\n\n            instance._onKeyUp({ target: null, keyCode: null });\n            instance._onInput({ target: null });\n          }));\n\n        it('is fired with a searchFloor of 0', () =>\n          new Promise((done) => {\n            instance.config.searchFloor = 0;\n            instance.input.value = 'qwerty';\n            instance.input.focus();\n            instance.passedElement.element.addEventListener('search', (event) => {\n              expect(event.detail).to.contains({\n                value: instance.input.value,\n                resultCount: 0,\n              });\n              done(true);\n            });\n\n            instance._onKeyUp({ target: null, keyCode: null });\n            instance._onInput({ target: null });\n          }));\n      });\n\n      describe('kmp', () => {\n        beforeEach(() => {\n          instance._searcher = new SearchByKMP(instance.config);\n        });\n        it('details are passed', () =>\n          new Promise((done) => {\n            const query = 'This is a <search> query & a \"test\" with characters that should not be sanitised.';\n\n            instance.input.value = query;\n            instance.input.focus();\n            instance.passedElement.element.addEventListener(\n              'search',\n              (event) => {\n                expect(event.detail).to.contains({\n                  value: query,\n                  resultCount: 0,\n                });\n                done(true);\n              },\n              { once: true },\n            );\n\n            instance._onKeyUp({ target: null, keyCode: null });\n            instance._onInput({ target: null });\n          }));\n\n        it('is fired with a searchFloor of 0', () =>\n          new Promise((done) => {\n            instance.config.searchFloor = 0;\n            instance.input.value = 'qwerty';\n            instance.input.focus();\n            instance.passedElement.element.addEventListener('search', (event) => {\n              expect(event.detail).to.contains({\n                value: instance.input.value,\n                resultCount: 0,\n              });\n              done(true);\n            });\n\n            instance._onKeyUp({ target: null, keyCode: null });\n            instance._onInput({ target: null });\n          }));\n      });\n\n      describe('prefix-filter', () => {\n        beforeEach(() => {\n          instance._searcher = new SearchByPrefixFilter(instance.config);\n        });\n        it('details are passed', () =>\n          new Promise((done) => {\n            const query = 'This is a <search> query & a \"test\" with characters that should not be sanitised.';\n\n            instance.input.value = query;\n            instance.input.focus();\n            instance.passedElement.element.addEventListener(\n              'search',\n              (event) => {\n                expect(event.detail).to.contains({\n                  value: query,\n                  resultCount: 0,\n                });\n                done(true);\n              },\n              { once: true },\n            );\n\n            instance._onKeyUp({ target: null, keyCode: null });\n            instance._onInput({ target: null });\n          }));\n\n        it('is fired with a searchFloor of 0', () =>\n          new Promise((done) => {\n            instance.config.searchFloor = 0;\n            instance.input.value = 'qwerty';\n            instance.input.focus();\n            instance.passedElement.element.addEventListener('search', (event) => {\n              expect(event.detail).to.contains({\n                value: instance.input.value,\n                resultCount: 0,\n              });\n              done(true);\n            });\n\n            instance._onKeyUp({ target: null, keyCode: null });\n            instance._onInput({ target: null });\n          }));\n      });\n    });\n  });\n\n  describe('private methods', () => {\n    describe('_generatePlaceholderValue', () => {\n      describe('select element', () => {\n        describe('when a placeholder option is defined', () => {\n          it('returns the text value of the placeholder option', () => {\n            const placeholderValue = 'I am a placeholder';\n\n            instance._isSelectElement = true;\n            instance.passedElement.placeholderOption = {\n              text: placeholderValue,\n            };\n\n            const value = instance._generatePlaceholderValue();\n            expect(value).to.equal(placeholderValue);\n          });\n        });\n\n        describe('when a placeholder option is not defined', () => {\n          it('returns null', () => {\n            instance._isSelectElement = true;\n            instance.passedElement.placeholderOption = undefined;\n\n            const value = instance._generatePlaceholderValue();\n            expect(value).to.equal(null);\n          });\n        });\n      });\n\n      describe('text input', () => {\n        describe('when the placeholder config option is set to true', () => {\n          describe('when the placeholderValue config option is defined', () => {\n            it('returns placeholderValue', () => {\n              const placeholderValue = 'I am a placeholder';\n\n              instance._isSelectElement = false;\n              instance.config.placeholder = true;\n              instance.config.placeholderValue = placeholderValue;\n              instance._hasNonChoicePlaceholder = true;\n\n              const value = instance._generatePlaceholderValue();\n              expect(value).to.equal(placeholderValue);\n            });\n          });\n        });\n\n        describe('when the placeholder config option is set to false', () => {\n          it('returns null', () => {\n            instance._isSelectElement = false;\n            instance.config.placeholder = false;\n\n            const value = instance._generatePlaceholderValue();\n            expect(value).to.equal(null);\n          });\n        });\n      });\n    });\n\n    describe('_onKeyDown', () => {\n      let items;\n      let hasItems;\n      let hasActiveDropdown;\n      let hasFocussedInput;\n\n      beforeEach(() => {\n        instance.showDropdown = stub();\n        instance._onSelectKey = stub();\n        instance._onEnterKey = stub();\n        instance._onEscapeKey = stub();\n        instance._onDirectionKey = stub();\n        instance._onDeleteKey = stub();\n\n        ({ items } = instance._store);\n        hasItems = instance.itemList.element.hasChildNodes();\n        hasActiveDropdown = instance.dropdown.isActive;\n        hasFocussedInput = instance.input.isFocussed;\n      });\n\n      describe('direction key', () => {\n        const keyCodes = [\n          [KeyCodeMap.UP_KEY, 'ArrowUp'],\n          [KeyCodeMap.DOWN_KEY, 'ArrowDown'],\n          [KeyCodeMap.PAGE_UP_KEY, 'PageUp'],\n          [KeyCodeMap.PAGE_DOWN_KEY, 'PageDown'],\n        ];\n\n        keyCodes.forEach(([keyCode, key]) => {\n          it(`calls _onDirectionKey with the expected arguments`, () => {\n            const event = {\n              keyCode,\n              key,\n            };\n\n            instance._onKeyDown(event);\n\n            expect(instance._onDirectionKey).to.have.been.calledWith(event, hasActiveDropdown);\n          });\n        });\n      });\n\n      describe('select key', () => {\n        it(`calls _onSelectKey with the expected arguments`, () => {\n          const event = {\n            keyCode: KeyCodeMap.A_KEY,\n            key: 'A',\n          };\n\n          instance._onKeyDown(event);\n\n          expect(instance._onSelectKey).to.have.been.calledWith(event, hasItems);\n        });\n      });\n\n      describe('enter key', () => {\n        it(`calls _onEnterKey with the expected arguments`, () => {\n          const event = {\n            keyCode: KeyCodeMap.ENTER_KEY,\n            key: 'Enter',\n          };\n\n          instance._onKeyDown(event);\n\n          expect(instance._onEnterKey).to.have.been.calledWith(event, hasActiveDropdown);\n        });\n      });\n\n      describe('delete key', () => {\n        // this is not an error; the constants are named the reverse of their assigned key names, according\n        // to their actual values, which appear to conform to the Windows VK mappings:\n        // 0x08 = 'Backspace', 0x2E = 'Delete'\n        // https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values#editing_keys\n        const keyCodes = [\n          [KeyCodeMap.DELETE_KEY, 'Backspace'],\n          [KeyCodeMap.BACK_KEY, 'Delete'],\n        ];\n\n        keyCodes.forEach(([keyCode, key]) => {\n          it(`calls _onDeleteKey with the expected arguments`, () => {\n            const event = {\n              keyCode,\n              key,\n            };\n\n            instance._onKeyDown(event);\n\n            expect(instance._onDeleteKey).to.have.been.calledWith(event, items, hasFocussedInput);\n          });\n        });\n      });\n    });\n\n    describe('_removeItem', () => {\n      beforeEach(() => {\n        instance._store.dispatch = stub();\n      });\n\n      afterEach(() => {\n        instance._store.dispatch.reset();\n      });\n\n      describe('when given an item to remove', () => {\n        const item: ChoiceFull = {\n          highlighted: false,\n          active: false,\n          disabled: false,\n          placeholder: false,\n          selected: false,\n          id: 1111,\n          value: 'test value',\n          label: 'test label',\n          group: null,\n          customProperties: {},\n          score: 0,\n          rank: 0,\n        };\n\n        it('dispatches a REMOVE_ITEM action to the store', () => {\n          instance._removeItem(item);\n\n          expect(instance._store.dispatch).to.have.been.calledWith(removeItem(item));\n        });\n\n        it('triggers a REMOVE_ITEM event on the passed element', () =>\n          new Promise((done) => {\n            passedElement.addEventListener(\n              'removeItem',\n              (event) => {\n                expect(event.detail).to.contains({\n                  id: item.id,\n                  value: item.value,\n                  label: item.label,\n                  customProperties: item.customProperties,\n                  groupValue: undefined,\n                });\n                done(true);\n              },\n              false,\n            );\n\n            instance._removeItem(item);\n          }));\n\n        describe('when the item belongs to a group', () => {\n          const group = {\n            id: 1,\n            label: 'testing',\n          };\n          const itemWithGroup = {\n            ...item,\n            value: 'testing',\n            group,\n          };\n\n          beforeEach(() => {\n            instance._store.getGroupById = stub();\n            instance._store.getGroupById.returns(group);\n          });\n\n          afterEach(() => {\n            instance._store.getGroupById.reset();\n          });\n\n          it(\"includes the group's value in the triggered event\", () =>\n            new Promise((done) => {\n              passedElement.addEventListener(\n                'removeItem',\n                (event) => {\n                  expect(event.detail).to.contains({\n                    id: itemWithGroup.id,\n                    value: itemWithGroup.value,\n                    label: itemWithGroup.label,\n                    customProperties: itemWithGroup.customProperties,\n                    groupValue: group.label,\n                  });\n\n                  done(true);\n                },\n                false,\n              );\n\n              instance._removeItem(itemWithGroup);\n            }));\n        });\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/scripts/components/container.test.ts",
    "content": "import { expect } from 'chai';\nimport { stub } from 'sinon';\nimport { DEFAULT_CLASSNAMES } from '../../../src';\nimport Container from '../../../src/scripts/components/container';\n\ndescribe('components/container', () => {\n  let instance;\n  let element;\n\n  beforeEach(() => {\n    element = document.createElement('div');\n    element.id = 'container';\n\n    document.body.appendChild(element);\n    instance = new Container({\n      element: document.getElementById('container') as HTMLElement,\n      classNames: DEFAULT_CLASSNAMES,\n      position: 'auto',\n      type: 'text',\n    });\n  });\n\n  afterEach(() => {\n    document.body.innerHTML = '';\n    element = null;\n    instance = null;\n  });\n\n  describe('constructor', () => {\n    it('assigns choices element to class', () => {\n      expect(instance.element).to.equal(element);\n    });\n\n    it('assigns classnames to class', () => {\n      expect(instance.classNames).to.deep.equal(DEFAULT_CLASSNAMES);\n    });\n  });\n\n  describe('shouldFlip', () => {\n    describe('passing dropdownPos', () => {\n      describe('position config option set to \"top\"', () => {\n        beforeEach(() => {\n          instance.position = 'top';\n        });\n\n        it('returns true', () => {\n          expect(instance.shouldFlip(100, 100)).to.equal(true);\n        });\n      });\n\n      describe('position config option set to \"bottom\"', () => {\n        beforeEach(() => {\n          instance.position = 'bottom';\n        });\n\n        it('returns false', () => {\n          expect(instance.shouldFlip(100, 100)).to.equal(false);\n        });\n      });\n    });\n  });\n\n  describe('setActiveDescendant', () => {\n    it(\"sets element's aria-activedescendant attribute with passed descendant ID\", () => {\n      const activeDescendantID = '1234';\n      expect(instance.element.getAttribute('aria-activedescendant')).to.equal(null);\n      instance.setActiveDescendant(activeDescendantID);\n      expect(instance.element.getAttribute('aria-activedescendant')).to.equal(activeDescendantID);\n    });\n  });\n\n  describe('removeActiveDescendant', () => {\n    it(\"remove elememnt's aria-activedescendant attribute\", () => {\n      const activeDescendantID = '1234';\n      instance.element.setAttribute('aria-activedescendant', activeDescendantID);\n      expect(instance.element.getAttribute('aria-activedescendant')).to.equal(activeDescendantID);\n      instance.removeActiveDescendant();\n      expect(instance.element.getAttribute('aria-activedescendant')).to.equal(null);\n    });\n  });\n\n  describe('open', () => {\n    beforeEach(() => {\n      instance.open();\n    });\n\n    it('adds open state class', () => {\n      expect(instance.element.classList.contains(DEFAULT_CLASSNAMES.openState)).to.equal(true);\n    });\n\n    it('sets aria-expanded attribute to true', () => {\n      expect(instance.element.getAttribute('aria-expanded')).to.equal('true');\n    });\n\n    it('sets isOpen flag to true', () => {\n      expect(instance.isOpen).to.equal(true);\n    });\n\n    describe('flipping dropdown', () => {\n      let shouldFlipStub;\n      beforeEach(() => {\n        shouldFlipStub = stub().returns(true);\n\n        instance.shouldFlip = shouldFlipStub;\n        instance.open();\n      });\n\n      afterEach(() => {\n        instance.shouldFlip.reset();\n      });\n\n      it('adds adds flipped state class', () => {\n        expect(instance.element.classList.contains(DEFAULT_CLASSNAMES.flippedState)).to.equal(true);\n      });\n\n      it('sets isFlipped flag to true', () => {\n        expect(instance.isFlipped).to.equal(true);\n      });\n    });\n  });\n\n  describe('close', () => {\n    beforeEach(() => {\n      instance.close();\n    });\n\n    it('adds open state class', () => {\n      expect(instance.element.classList.contains(DEFAULT_CLASSNAMES.openState)).to.equal(false);\n    });\n\n    it('sets aria-expanded attribute to true', () => {\n      expect(instance.element.getAttribute('aria-expanded')).to.equal('false');\n    });\n\n    it('sets isOpen flag to true', () => {\n      expect(instance.isOpen).to.equal(false);\n    });\n\n    describe('flipped dropdown', () => {\n      beforeEach(() => {\n        instance.isFlipped = true;\n        instance.close();\n      });\n\n      it('removes adds flipped state class', () => {\n        expect(instance.element.classList.contains(DEFAULT_CLASSNAMES.flippedState)).to.equal(false);\n      });\n\n      it('sets isFlipped flag to false', () => {\n        expect(instance.isFlipped).to.equal(false);\n      });\n    });\n  });\n\n  describe('addFocusState', () => {\n    beforeEach(() => {\n      instance.removeLoadingState();\n    });\n\n    it('adds focus state class', () => {\n      expect(instance.element.classList.contains(DEFAULT_CLASSNAMES.focusState)).to.equal(false);\n      instance.addFocusState();\n      expect(instance.element.classList.contains(DEFAULT_CLASSNAMES.focusState)).to.equal(true);\n    });\n  });\n\n  describe('removeFocusState', () => {\n    beforeEach(() => {\n      instance.addFocusState();\n    });\n\n    it('removes focus state class', () => {\n      expect(instance.element.classList.contains(DEFAULT_CLASSNAMES.focusState)).to.equal(true);\n      instance.removeFocusState();\n      expect(instance.element.classList.contains(DEFAULT_CLASSNAMES.focusState)).to.equal(false);\n    });\n  });\n\n  describe('enable', () => {\n    beforeEach(() => {\n      instance.disable();\n    });\n\n    it('removes disabled state class', () => {\n      expect(instance.element.classList.contains(DEFAULT_CLASSNAMES.disabledState)).to.equal(true);\n      instance.enable();\n      expect(instance.element.classList.contains(DEFAULT_CLASSNAMES.disabledState)).to.equal(false);\n    });\n\n    it('removes aria-disabled attribute', () => {\n      expect(instance.element.getAttribute('aria-disabled')).to.equal('true');\n      instance.enable();\n      expect(instance.element.getAttribute('aria-disabled')).to.equal(null);\n    });\n\n    it('sets isDisabled flag to true', () => {\n      instance.enable();\n      expect(instance.isDisabled).to.equal(false);\n    });\n\n    describe('select one element', () => {\n      beforeEach(() => {\n        instance.type = 'select-one';\n        instance.enable();\n      });\n\n      it('sets tabindex attribute', () => {\n        expect(instance.element.getAttribute('tabindex')).to.equal('0');\n      });\n    });\n  });\n\n  describe('disable', () => {\n    beforeEach(() => {\n      instance.enable();\n    });\n\n    it('removes disabled state class', () => {\n      expect(instance.element.classList.contains(DEFAULT_CLASSNAMES.disabledState)).to.equal(false);\n      instance.disable();\n      expect(instance.element.classList.contains(DEFAULT_CLASSNAMES.disabledState)).to.equal(true);\n    });\n\n    it('removes aria-disabled attribute', () => {\n      expect(instance.element.getAttribute('aria-disabled')).to.equal(null);\n      instance.disable();\n      expect(instance.element.getAttribute('aria-disabled')).to.equal('true');\n    });\n\n    it('sets isDisabled flag to true', () => {\n      instance.disable();\n      expect(instance.isDisabled).to.equal(true);\n    });\n\n    describe('select one element', () => {\n      beforeEach(() => {\n        instance.type = 'select-one';\n        instance.disable();\n      });\n\n      it('sets tabindex attribute', () => {\n        expect(instance.element.getAttribute('tabindex')).to.equal('-1');\n      });\n    });\n  });\n\n  describe('wrap', () => {\n    let elementToWrap;\n\n    beforeEach(() => {\n      elementToWrap = document.createElement('div');\n      elementToWrap.id = 'wrap-test';\n      document.body.appendChild(elementToWrap);\n    });\n\n    afterEach(() => {\n      document.getElementById('wrap-test')!.remove();\n    });\n\n    it('wraps passed element inside element', () => {\n      expect(instance.element.querySelector('div#wrap-test')).to.equal(null);\n      instance.wrap(document.querySelector('div#wrap-test'));\n      expect(instance.element.querySelector('div#wrap-test')).to.equal(elementToWrap);\n    });\n  });\n\n  describe('unwrap', () => {\n    let elementToUnwrap;\n\n    beforeEach(() => {\n      elementToUnwrap = document.createElement('div');\n      elementToUnwrap.id = 'unwrap-test';\n      document.body.appendChild(elementToUnwrap);\n      instance.wrap(document.getElementById('unwrap-test'));\n    });\n\n    afterEach(() => {\n      document.body.removeChild(document.getElementById('unwrap-test') as Node);\n    });\n\n    it('moves wrapped element outside of element', () => {\n      expect(instance.element.querySelector('div#unwrap-test')).to.be.instanceof(HTMLElement);\n      instance.unwrap(elementToUnwrap);\n      expect(instance.element.querySelector('div#unwrap-test')).to.equal(null);\n      expect(document.querySelector('div#unwrap-test')).to.be.instanceof(HTMLElement);\n    });\n\n    it('removes element from DOM', () => {\n      expect(document.getElementById('container')).to.not.equal(null);\n      instance.unwrap(elementToUnwrap);\n      expect(document.getElementById('container')).to.equal(null);\n    });\n  });\n\n  describe('addLoadingState', () => {\n    beforeEach(() => {\n      instance.removeLoadingState();\n    });\n\n    it('adds loading state class', () => {\n      expect(instance.element.classList.contains(DEFAULT_CLASSNAMES.loadingState)).to.equal(false);\n      instance.addLoadingState();\n      expect(instance.element.classList.contains(DEFAULT_CLASSNAMES.loadingState)).to.equal(true);\n    });\n\n    it('sets aria-busy attribute to true', () => {\n      expect(instance.element.getAttribute('aria-busy')).to.equal(null);\n      instance.addLoadingState();\n      expect(instance.element.getAttribute('aria-busy')).to.equal('true');\n    });\n\n    it('sets isLoading flag to false', () => {\n      expect(instance.isLoading).to.equal(false);\n      instance.addLoadingState();\n      expect(instance.isLoading).to.equal(true);\n    });\n  });\n\n  describe('removeLoadingState', () => {\n    beforeEach(() => {\n      instance.addLoadingState();\n    });\n\n    it('removes loading state class', () => {\n      expect(instance.element.classList.contains(DEFAULT_CLASSNAMES.loadingState)).to.equal(true);\n      instance.removeLoadingState();\n      expect(instance.element.classList.contains(DEFAULT_CLASSNAMES.loadingState)).to.equal(false);\n    });\n\n    it('removes aria-busy attribute', () => {\n      expect(instance.element.getAttribute('aria-busy')).to.equal('true');\n      instance.removeLoadingState();\n      expect(instance.element.getAttribute('aria-busy')).to.equal(null);\n    });\n\n    it('sets isLoading flag to true', () => {\n      expect(instance.isLoading).to.equal(true);\n      instance.removeLoadingState();\n      expect(instance.isLoading).to.equal(false);\n    });\n  });\n});\n"
  },
  {
    "path": "test/scripts/components/dropdown.test.ts",
    "content": "import { expect } from 'chai';\nimport { DEFAULT_CLASSNAMES } from '../../../src';\nimport Dropdown from '../../../src/scripts/components/dropdown';\nimport { getClassNames } from '../../../src/scripts/lib/utils';\n\ndescribe('components/dropdown', () => {\n  let instance: Dropdown | null;\n  let choicesElement: HTMLDivElement;\n\n  beforeEach(() => {\n    choicesElement = document.createElement('div');\n    document.body.appendChild(choicesElement);\n    instance = new Dropdown({\n      element: choicesElement,\n      type: 'text',\n      classNames: DEFAULT_CLASSNAMES,\n    });\n  });\n\n  afterEach(() => {\n    document.body.innerHTML = '';\n    instance = null;\n  });\n\n  describe('constructor', () => {\n    it('assigns choices element to instance', () => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      expect(instance.element).to.equal(choicesElement);\n    });\n\n    it('assigns classnames to instance', () => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      expect(instance.classNames).to.deep.equal(DEFAULT_CLASSNAMES);\n    });\n  });\n\n  describe('show', () => {\n    let actualResponse;\n\n    beforeEach(() => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      actualResponse = instance.show();\n    });\n\n    afterEach(() => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      instance.hide();\n    });\n\n    it('adds active class', () => {\n      getClassNames(DEFAULT_CLASSNAMES.activeState).forEach((c) => {\n        expect(instance).to.not.be.null;\n        if (!instance) {\n          return;\n        }\n        expect(instance.element.classList.contains(c)).to.equal(true);\n      });\n    });\n\n    it('sets expanded attribute', () => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      expect(instance.element.getAttribute('aria-expanded')).to.equal('true');\n    });\n\n    it('sets isActive instance flag', () => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      expect(instance.isActive).to.equal(true);\n    });\n\n    it('returns instance', () => {\n      expect(actualResponse).to.deep.equal(instance);\n    });\n  });\n\n  describe('hide', () => {\n    let actualResponse;\n\n    beforeEach(() => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      actualResponse = instance.hide();\n    });\n\n    afterEach(() => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      instance.show();\n    });\n\n    it('adds active class', () => {\n      getClassNames(DEFAULT_CLASSNAMES.activeState).forEach((c) => {\n        expect(instance).to.not.be.null;\n        if (!instance) {\n          return;\n        }\n        expect(instance.element.classList.contains(c)).to.equal(false);\n      });\n    });\n\n    it('sets expanded attribute', () => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      expect(instance.element.getAttribute('aria-expanded')).to.equal('false');\n    });\n\n    it('sets isActive instance flag', () => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      expect(instance.isActive).to.equal(false);\n    });\n\n    it('returns instance', () => {\n      expect(actualResponse).to.deep.equal(instance);\n    });\n  });\n});\n"
  },
  {
    "path": "test/scripts/components/input.test.ts",
    "content": "import { expect } from 'chai';\nimport { stub } from 'sinon';\nimport { DEFAULT_CLASSNAMES } from '../../../src';\nimport Input from '../../../src/scripts/components/input';\n\ndescribe('components/input', () => {\n  let instance;\n  let choicesElement;\n\n  beforeEach(() => {\n    choicesElement = document.createElement('input');\n    instance = new Input({\n      element: choicesElement,\n      type: 'text',\n      classNames: DEFAULT_CLASSNAMES,\n      preventPaste: false,\n    });\n  });\n\n  afterEach(() => {\n    document.body.innerHTML = '';\n    instance = null;\n  });\n\n  describe('constructor', () => {\n    it('assigns choices element to class', () => {\n      expect(instance.element).to.equal(choicesElement);\n    });\n\n    it('assigns classnames to class', () => {\n      expect(instance.classNames).to.deep.equal(DEFAULT_CLASSNAMES);\n    });\n  });\n\n  describe('addEventListeners', () => {\n    let addEventListenerStub;\n\n    beforeEach(() => {\n      addEventListenerStub = stub(instance.element, 'addEventListener');\n    });\n\n    afterEach(() => {\n      addEventListenerStub.restore();\n    });\n\n    it('adds event listeners', () => {\n      instance.addEventListeners();\n      expect(['input', 'paste', 'focus', 'blur']).to.have.members(\n        Array.from({ length: addEventListenerStub.callCount }, (_, i) => addEventListenerStub.getCall(i).args[0]),\n      );\n    });\n  });\n\n  describe('removeEventListeners', () => {\n    let removeEventListenerStub;\n\n    beforeEach(() => {\n      removeEventListenerStub = stub(instance.element, 'removeEventListener');\n    });\n\n    afterEach(() => {\n      removeEventListenerStub.restore();\n    });\n\n    it('removes event listeners', () => {\n      instance.removeEventListeners();\n      expect(removeEventListenerStub.callCount).to.equal(4);\n      expect(removeEventListenerStub.getCall(0).args[0]).to.equal('input');\n      expect(removeEventListenerStub.getCall(1).args[0]).to.equal('paste');\n      expect(removeEventListenerStub.getCall(2).args[0]).to.equal('focus');\n      expect(removeEventListenerStub.getCall(3).args[0]).to.equal('blur');\n    });\n  });\n\n  describe('_onInput', () => {\n    let setWidthStub;\n\n    beforeEach(() => {\n      setWidthStub = stub(instance, 'setWidth');\n    });\n\n    afterEach(() => {\n      setWidthStub.restore();\n    });\n\n    describe('when element is select one', () => {\n      it('does not set input width', () => {\n        instance.type = 'select-one';\n        instance._onInput();\n        expect(setWidthStub.callCount).to.equal(0);\n      });\n    });\n\n    describe('when element is not a select one', () => {\n      it('sets input width', () => {\n        instance.type = 'text';\n        instance._onInput();\n        expect(setWidthStub.callCount).to.equal(1);\n      });\n    });\n  });\n\n  describe('_onPaste', () => {\n    let eventMock;\n\n    beforeEach(() => {\n      eventMock = {\n        preventDefault: stub(),\n        target: instance.element,\n      };\n    });\n\n    describe('when pasting is disabled and target is the element', () => {\n      it('prevents default pasting behaviour', () => {\n        instance.preventPaste = true;\n        instance._onPaste(eventMock);\n        expect(eventMock.preventDefault.callCount).to.equal(1);\n      });\n    });\n\n    describe('when pasting is enabled', () => {\n      it('does not prevent default pasting behaviour', () => {\n        instance.preventPaste = false;\n        instance._onPaste(eventMock);\n        expect(eventMock.preventDefault.callCount).to.equal(0);\n      });\n    });\n  });\n\n  describe('_onFocus', () => {\n    it('sets isFocussed flag to true', () => {\n      expect(instance.isFocussed).to.equal(false);\n      instance._onFocus();\n      expect(instance.isFocussed).to.equal(true);\n    });\n  });\n\n  describe('_onBlur', () => {\n    it('sets isFocussed flag to false', () => {\n      instance.isFocussed = true;\n      instance._onBlur();\n      expect(instance.isFocussed).to.equal(false);\n    });\n  });\n\n  describe('enable', () => {\n    beforeEach(() => {\n      instance.element.setAttribute('disabled', '');\n      instance.isDisabled = true;\n      instance.enable();\n    });\n\n    it('removes disabled attribute', () => {\n      expect(instance.element.getAttribute('disabled')).to.equal(null);\n    });\n\n    it('sets isDisabled flag to false', () => {\n      expect(instance.isDisabled).to.equal(false);\n    });\n  });\n\n  describe('disable', () => {\n    beforeEach(() => {\n      instance.element.removeAttribute('disabled', '');\n      instance.isDisabled = false;\n      instance.disable();\n    });\n\n    it('removes disabled attribute', () => {\n      expect(instance.element.getAttribute('disabled')).to.equal('');\n    });\n\n    it('sets isDisabled flag to false', () => {\n      expect(instance.isDisabled).to.equal(true);\n    });\n  });\n\n  describe('focus', () => {\n    let focusStub;\n\n    beforeEach(() => {\n      focusStub = stub(instance.element, 'focus');\n    });\n\n    afterEach(() => {\n      focusStub.restore();\n    });\n\n    describe('when element is not focussed', () => {\n      it('focuses element if isFocussed flag is set to false', () => {\n        instance.isFocussed = true;\n        instance.focus();\n        expect(focusStub.callCount).to.equal(0);\n      });\n    });\n\n    describe('when element is focussed', () => {\n      it('focuses element if isFocussed flag is set to false', () => {\n        instance.isFocussed = false;\n        instance.focus();\n        expect(focusStub.callCount).to.equal(1);\n      });\n    });\n  });\n\n  describe('blur', () => {\n    let blurStub;\n\n    beforeEach(() => {\n      blurStub = stub(instance.element, 'blur');\n    });\n\n    afterEach(() => {\n      blurStub.restore();\n    });\n\n    describe('when element is not focussed', () => {\n      it(\"doesn't blur element\", () => {\n        instance.isFocussed = false;\n        instance.blur();\n        expect(blurStub.callCount).to.equal(0);\n      });\n    });\n\n    describe('when element is focussed', () => {\n      it('blurs element', () => {\n        instance.isFocussed = true;\n        instance.blur();\n        expect(blurStub.callCount).to.equal(1);\n      });\n    });\n  });\n\n  describe('clear', () => {\n    let setWidthStub;\n\n    beforeEach(() => {\n      setWidthStub = stub(instance, 'setWidth');\n    });\n\n    afterEach(() => {\n      setWidthStub.restore();\n    });\n\n    it(\"removes the element's value if it has one\", () => {\n      instance.element.value = 'test';\n      expect(instance.element.value).to.equal('test');\n      instance.clear();\n      expect(instance.element.value).to.equal('');\n    });\n\n    it(\"sets the element's width if flag passed\", () => {\n      expect(setWidthStub.callCount).to.equal(0);\n      instance.clear(true);\n      expect(setWidthStub.callCount).to.equal(1);\n    });\n\n    it('returns instance', () => {\n      const response = instance.clear();\n      expect(response).to.deep.equal(instance);\n    });\n  });\n\n  describe('setWidth', () => {\n    it('sets the width of the element based on input value and placeholder', () => {\n      instance.placeholder = 'This is a placeholder';\n      instance.element.value = 'This is a value';\n      expect(instance.element.style.width).to.not.equal('16ch');\n      instance.setWidth();\n      expect(instance.element.style.width).to.equal('16ch');\n      expect(instance.element.style.minWidth).to.equal('22ch');\n    });\n  });\n\n  describe('placeholder setter', () => {\n    it('sets value of element to passed placeholder', () => {\n      const placeholder = 'test';\n      expect(instance.element.placeholder).to.equal('');\n      instance.placeholder = placeholder;\n      expect(instance.element.placeholder).to.equal(placeholder);\n    });\n  });\n\n  describe('value setter', () => {\n    it('sets value of element to passed value', () => {\n      const value = 'test';\n      expect(instance.element.value).to.equal('');\n      instance.value = value;\n      expect(instance.element.value).to.equal(value);\n    });\n\n    it('casts value to string', () => {\n      const value = 1234;\n      instance.value = value;\n      expect(instance.element.value).to.equal(`${value}`);\n    });\n  });\n\n  describe('value getter', () => {\n    it('sets value of element to passed value', () => {\n      const value = 'test';\n      instance.element.value = value;\n      expect(instance.value).to.equal(value);\n    });\n  });\n\n  describe('setActiveDescendant', () => {\n    it(\"sets element's aria-activedescendant attribute with passed descendant ID\", () => {\n      const activeDescendantID = '1234';\n      expect(instance.element.getAttribute('aria-activedescendant')).to.equal(null);\n      instance.setActiveDescendant(activeDescendantID);\n      expect(instance.element.getAttribute('aria-activedescendant')).to.equal(activeDescendantID);\n    });\n  });\n\n  describe('removeActiveDescendant', () => {\n    it(\"remove elememnt's aria-activedescendant attribute\", () => {\n      const activeDescendantID = '1234';\n      instance.element.setAttribute('aria-activedescendant', activeDescendantID);\n      expect(instance.element.getAttribute('aria-activedescendant')).to.equal(activeDescendantID);\n      instance.removeActiveDescendant();\n      expect(instance.element.getAttribute('aria-activedescendant')).to.equal(null);\n    });\n  });\n});\n"
  },
  {
    "path": "test/scripts/components/list.test.ts",
    "content": "import { expect } from 'chai';\nimport List from '../../../src/scripts/components/list';\n\ndescribe('components/list', () => {\n  let instance: List | null;\n  let choicesElement: HTMLDivElement;\n\n  beforeEach(() => {\n    choicesElement = document.createElement('div');\n    instance = new List({\n      element: choicesElement,\n    });\n  });\n\n  afterEach(() => {\n    document.body.innerHTML = '';\n    instance = null;\n  });\n\n  describe('constructor', () => {\n    it('assigns choices element to class', () => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      expect(instance.element).to.equal(choicesElement);\n    });\n\n    it('sets the height of the element', () => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      expect(instance.height).to.deep.equal(choicesElement.scrollTop);\n    });\n  });\n\n  describe('scrollToTop', () => {\n    it(\"sets the position's scroll position to 0\", () => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      instance.element.scrollTop = 10;\n      instance.scrollToTop();\n      expect(instance.element.scrollTop).to.equal(0);\n    });\n  });\n});\n"
  },
  {
    "path": "test/scripts/components/wrapped-element.test.ts",
    "content": "import { expect } from 'chai';\nimport { getClassNames } from '../../../src/scripts/lib/utils';\nimport { DEFAULT_CLASSNAMES, EventMap, EventType } from '../../../src';\nimport WrappedElement from '../../../src/scripts/components/wrapped-element';\n\ndescribe('components/wrappedElement', () => {\n  let instance: WrappedElement<HTMLSelectElement | HTMLInputElement> | null;\n  let element: HTMLSelectElement;\n\n  beforeEach(() => {\n    element = document.createElement('select');\n    instance = new WrappedElement({\n      element,\n      classNames: DEFAULT_CLASSNAMES,\n    });\n  });\n\n  afterEach(() => {\n    document.body.innerHTML = '';\n    instance = null;\n  });\n\n  describe('constructor', () => {\n    it('assigns choices element to class', () => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      expect(instance.element).to.equal(element);\n    });\n\n    it('assigns classnames to class', () => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      expect(instance.classNames).to.deep.equal(DEFAULT_CLASSNAMES);\n    });\n\n    it('sets isDisabled flag to false', () => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      expect(instance.isDisabled).to.deep.equal(false);\n    });\n  });\n\n  describe('value getter', () => {\n    it('returns element value', () => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      expect(instance.value).to.deep.equal(element.value);\n    });\n  });\n\n  describe('isActive getter', () => {\n    it('returns whether the \"data-choice\" attribute is set to \"active\"', () => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      instance.element.dataset.choice = 'active';\n      expect(instance.isActive).to.equal(true);\n\n      instance.element.dataset.choice = 'inactive';\n      expect(instance.isActive).to.equal(false);\n    });\n  });\n\n  describe('dir getter', () => {\n    it('returns the direction of the element', () => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      expect(instance.dir).to.equal(instance.element.dir);\n    });\n  });\n\n  describe('conceal', () => {\n    let originalStyling: string;\n\n    beforeEach(() => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      originalStyling = 'color:red';\n      instance.element.setAttribute('style', originalStyling);\n    });\n\n    it('hides element', () => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      instance.conceal();\n      expect(instance.element.tabIndex).to.equal(-1);\n\n      const classesToCheck = getClassNames(instance.classNames.input);\n      expect(\n        Array.from(instance.element.classList).some((className) => classesToCheck.indexOf(className) !== -1),\n      ).to.equal(true);\n      expect(instance.element.hidden).to.be.true;\n      expect(instance.element.getAttribute('data-choice')).to.equal('active');\n      expect(instance.element.getAttribute('data-choice-orig-style')).to.equal(originalStyling);\n    });\n  });\n\n  describe('reveal', () => {\n    let originalStyling: string;\n\n    beforeEach(() => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      originalStyling = 'color:red';\n      instance.element.setAttribute('data-choice-orig-style', originalStyling);\n    });\n\n    it('shows element', () => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      instance.reveal();\n      expect(instance.element.tabIndex).to.equal(0);\n\n      const classesToCheck = getClassNames(instance.classNames.input);\n      expect(\n        Array.from(instance.element.classList).some((className) => classesToCheck.indexOf(className) !== -1),\n      ).to.equal(false);\n      expect(instance.element.hidden).to.be.false;\n      expect(instance.element.getAttribute('style')).to.equal(originalStyling);\n      expect(instance.element.getAttribute('aria-hidden')).to.equal(null);\n      expect(instance.element.getAttribute('data-choice')).to.equal(null);\n      expect(instance.element.getAttribute('data-choice-orig-style')).to.equal(null);\n    });\n  });\n\n  describe('enable', () => {\n    beforeEach(() => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      instance.disable();\n    });\n\n    it('removes disabled attribute', () => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      expect(instance.element.hasAttribute('disabled')).to.equal(true);\n      instance.enable();\n      expect(instance.element.hasAttribute('disabled')).to.equal(false);\n    });\n\n    it('sets elements disabled state to false', () => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      expect(instance.element.disabled).to.equal(true);\n      instance.enable();\n      expect(instance.element.disabled).to.equal(false);\n    });\n\n    it('sets isDisabled flag to false', () => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      expect(instance.isDisabled).to.equal(true);\n      instance.enable();\n      expect(instance.isDisabled).to.equal(false);\n    });\n  });\n\n  describe('disable', () => {\n    beforeEach(() => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      instance.enable();\n    });\n\n    it('sets disabled attribute (to blank string)', () => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      expect(instance.element.hasAttribute('disabled')).to.equal(false);\n      instance.disable();\n      expect(instance.element.getAttribute('disabled')).to.equal('');\n    });\n\n    it('sets elements disabled state to true', () => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      expect(instance.element.disabled).to.equal(false);\n      instance.disable();\n      expect(instance.element.disabled).to.equal(true);\n    });\n\n    it('sets isDisabled flag to true', () => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      expect(instance.isDisabled).to.equal(false);\n      instance.disable();\n      expect(instance.isDisabled).to.equal(true);\n    });\n  });\n\n  describe('triggerEvent', () => {\n    it('fires event on element using passed eventType and data', () =>\n      new Promise((done) => {\n        const data: EventMap[EventType.change]['detail'] = {\n          value: '',\n        };\n        expect(instance).to.not.be.null;\n        if (!instance) {\n          return;\n        }\n\n        instance.element.addEventListener(EventType.change, ({ detail }: CustomEvent) => {\n          expect(detail).to.deep.equal(data);\n          done(true);\n        });\n\n        instance.triggerEvent(EventType.change, data);\n      }));\n  });\n});\n"
  },
  {
    "path": "test/scripts/components/wrapped-input.test.ts",
    "content": "import { expect } from 'chai';\nimport { stub } from 'sinon';\nimport { DEFAULT_CLASSNAMES } from '../../../src';\nimport WrappedElement from '../../../src/scripts/components/wrapped-element';\nimport WrappedInput from '../../../src/scripts/components/wrapped-input';\n\ndescribe('components/wrappedInput', () => {\n  let instance: WrappedInput | null;\n  let element: HTMLInputElement;\n\n  beforeEach(() => {\n    element = document.createElement('input');\n    instance = new WrappedInput({\n      element,\n      classNames: DEFAULT_CLASSNAMES,\n    });\n  });\n\n  afterEach(() => {\n    document.body.innerHTML = '';\n    instance = null;\n  });\n\n  describe('constructor', () => {\n    it('assigns choices element to class', () => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      expect(instance.element).to.equal(element);\n    });\n\n    it('assigns classnames to class', () => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      expect(instance.classNames).to.deep.equal(DEFAULT_CLASSNAMES);\n    });\n  });\n\n  describe('inherited methods', () => {\n    const methods: string[] = ['conceal', 'reveal', 'enable', 'disable'];\n\n    methods.forEach((method) => {\n      describe(method, () => {\n        beforeEach(() => {\n          stub(WrappedElement.prototype, method as keyof WrappedElement<HTMLInputElement>);\n        });\n\n        afterEach(() => {\n          WrappedElement.prototype[method].restore();\n        });\n\n        it(`calls super.${method}`, () => {\n          expect(instance).to.not.be.null;\n          if (!instance) {\n            return;\n          }\n          expect(WrappedElement.prototype[method].called).to.equal(false);\n          instance[method]();\n          expect(WrappedElement.prototype[method].called).to.equal(true);\n        });\n      });\n    });\n  });\n\n  describe('value setter', () => {\n    it('sets the value of the input to the given value', () => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      const newValue = 'Value 1, Value 2, Value 3';\n      expect(instance.element.value).to.equal('');\n      instance.value = newValue;\n      expect(instance.value).to.equal(newValue);\n    });\n  });\n});\n"
  },
  {
    "path": "test/scripts/components/wrapped-select.test.ts",
    "content": "import { expect } from 'chai';\nimport { stub, spy } from 'sinon';\nimport WrappedElement from '../../../src/scripts/components/wrapped-element';\nimport WrappedSelect from '../../../src/scripts/components/wrapped-select';\nimport Templates from '../../../src/scripts/templates';\nimport { DEFAULT_CLASSNAMES } from '../../../src';\n\ndescribe('components/wrappedSelect', () => {\n  let instance: WrappedSelect | null;\n  let element: HTMLSelectElement;\n\n  beforeEach(() => {\n    element = document.createElement('select');\n    element.id = 'target';\n    for (let i = 0; i <= 4; i++) {\n      const option = document.createElement('option');\n\n      if (i === 0) {\n        option.value = '';\n        option.innerHTML = 'Placeholder label';\n      } else {\n        option.value = `Value ${i}`;\n        if (i % 2 === 0) {\n          option.innerHTML = `Label ${i}`;\n        } else {\n          option.label = `Label ${i}`;\n        }\n      }\n\n      if (i === 1) {\n        option.setAttribute('placeholder', '');\n      }\n\n      element.appendChild(option);\n    }\n    document.body.appendChild(element);\n\n    instance = new WrappedSelect({\n      element: document.getElementById('target') as HTMLSelectElement,\n      classNames: DEFAULT_CLASSNAMES,\n      template: spy(Templates.option),\n      extractPlaceholder: true,\n    });\n  });\n\n  afterEach(() => {\n    document.body.innerHTML = '';\n    instance = null;\n  });\n\n  describe('constructor', () => {\n    it('assigns choices element to class', () => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      expect(instance.element).to.equal(element);\n    });\n\n    it('assigns classnames to class', () => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      expect(instance.classNames).to.deep.equal(DEFAULT_CLASSNAMES);\n    });\n  });\n\n  describe('inherited methods', () => {\n    const methods: string[] = ['conceal', 'reveal', 'enable', 'disable'];\n\n    methods.forEach((method) => {\n      beforeEach(() => {\n        stub(WrappedElement.prototype, method as keyof WrappedElement<HTMLSelectElement>);\n      });\n\n      afterEach(() => {\n        WrappedElement.prototype[method].restore();\n      });\n\n      describe(method, () => {\n        it(`calls super.${method}`, () => {\n          expect(instance).to.not.be.null;\n          if (!instance) {\n            return;\n          }\n          expect(WrappedElement.prototype[method].called).to.equal(false);\n          instance[method]();\n          expect(WrappedElement.prototype[method].called).to.equal(true);\n        });\n      });\n    });\n  });\n\n  describe('placeholderOption getter', () => {\n    it('returns option element with empty value attribute', () => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      expect(instance.placeholderOption).to.be.instanceOf(HTMLOptionElement);\n      if (instance.placeholderOption) {\n        expect(instance.placeholderOption.value).to.equal('');\n      }\n    });\n\n    it('returns option element with placeholder attribute as fallback', () => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      expect(instance.element.firstChild).to.not.be.null;\n      if (instance.element.firstChild) {\n        instance.element.removeChild(instance.element.firstChild);\n      }\n\n      expect(instance.placeholderOption).to.be.instanceOf(HTMLOptionElement);\n      if (instance.placeholderOption) {\n        expect(instance.placeholderOption.value).to.equal('Value 1');\n      }\n    });\n  });\n\n  describe('options getter', () => {\n    it('returns all option elements', () => {\n      expect(instance).to.not.be.null;\n      if (!instance) {\n        return;\n      }\n      const optionsAsChoices = instance.optionsAsChoices();\n      expect(optionsAsChoices).to.be.an('array');\n    });\n  });\n});\n"
  },
  {
    "path": "test/scripts/lib/utils.test.ts",
    "content": "/* eslint-disable no-new-wrappers */\nimport { expect } from 'chai';\nimport { stub } from 'sinon';\n\nimport {\n  cloneObject,\n  diff,\n  dispatchEvent,\n  generateId,\n  sanitise,\n  parseCustomProperties,\n  sortByAlpha,\n  sortByScore,\n  sortByRank,\n} from '../../../src/scripts/lib/utils';\nimport { EventType } from '../../../src';\n\ndescribe('utils', () => {\n  describe('generateId', () => {\n    describe('when given element has id value', () => {\n      it('generates a unique prefixed id based on given elements id', () => {\n        const element = document.createElement('select');\n        element.id = 'test-id';\n        const prefix = 'test-prefix';\n\n        const output = generateId(element, prefix);\n\n        expect(output).to.equal(`${prefix}-${element.id}`);\n      });\n    });\n\n    describe('when given element has no id value but name value', () => {\n      it('generates a unique prefixed id based on given elements name plus 2 random characters', () => {\n        const element = document.createElement('select');\n        element.name = 'test-name';\n        const prefix = 'test-prefix';\n\n        const output = generateId(element, prefix);\n        const expectedOutput = `${prefix}-${element.name}-`;\n\n        expect(output).to.contain(expectedOutput);\n        expect(output).to.have.length(expectedOutput.length + 2);\n      });\n    });\n\n    describe('when given element has no id value and no name value', () => {\n      it('generates a unique prefixed id based on 4 random characters', () => {\n        const element = document.createElement('select');\n        const prefix = 'test-prefix';\n\n        const output = generateId(element, prefix);\n        const expectedOutput = `${prefix}-`;\n\n        expect(output).to.contain(expectedOutput);\n        expect(output).to.have.length(expectedOutput.length + 4);\n      });\n    });\n  });\n\n  describe('sanitise', () => {\n    describe('when passing a parameter that is not a string', () => {\n      it('returns the passed argument', () => {\n        const value = {\n          test: true,\n        };\n        const output = sanitise(value);\n        expect(output).to.equal(value);\n      });\n    });\n\n    describe('when passing a string', () => {\n      it('strips HTML from value', () => {\n        const value = '<script>somethingMalicious();</script>';\n        const output = sanitise(value);\n        expect(output).to.equal('&lt;script&gt;somethingMalicious();&lt;/script&gt;');\n      });\n    });\n  });\n\n  describe('sortByAlpha', () => {\n    describe('sorting an array', () => {\n      it('sorts by value alphabetically', () => {\n        const values = [\n          { value: 'The Strokes' },\n          { value: 'Arctic Monkeys' },\n          { value: 'Oasis' },\n          { value: 'Tame Impala' },\n        ];\n\n        const output = values.sort(sortByAlpha);\n\n        expect(output).to.deep.equal([\n          { value: 'Arctic Monkeys' },\n          { value: 'Oasis' },\n          { value: 'Tame Impala' },\n          { value: 'The Strokes' },\n        ]);\n      });\n\n      it('sorts by label alphabetically', () => {\n        const values = [\n          { value: '0', label: 'The Strokes' },\n          { value: '0', label: 'Arctic Monkeys' },\n          { value: '0', label: 'Oasis' },\n          { value: '0', label: 'Tame Impala' },\n        ];\n\n        const output = values.sort(sortByAlpha);\n\n        expect(output).to.deep.equal([\n          { value: '0', label: 'Arctic Monkeys' },\n          { value: '0', label: 'Oasis' },\n          { value: '0', label: 'Tame Impala' },\n          { value: '0', label: 'The Strokes' },\n        ]);\n      });\n    });\n  });\n\n  describe('sortByScore', () => {\n    describe('sorting an array', () => {\n      it('sorts by score ascending', () => {\n        const values = [{ score: 10 }, { score: 3001 }, { score: 124 }, { score: 400 }];\n\n        const output = values.sort(sortByScore);\n\n        expect(output).to.deep.equal([{ score: 10 }, { score: 124 }, { score: 400 }, { score: 3001 }]);\n      });\n    });\n  });\n\n  describe('sortByRank', () => {\n    describe('sorting an array', () => {\n      it('sorts by rank ascending', () => {\n        const values = [{ rank: 10 }, { rank: 3001 }, { rank: 124 }, { rank: 400 }];\n\n        const output = values.sort(sortByRank);\n\n        expect(output).to.deep.equal([{ rank: 10 }, { rank: 124 }, { rank: 400 }, { rank: 3001 }]);\n      });\n    });\n  });\n\n  describe('dispatchEvent', () => {\n    it('dispatches custom event of given type on given element', () => {\n      const fakeElement = {\n        dispatchEvent: stub(),\n      };\n      const eventType = EventType.addItem;\n      const customArgs = {\n        testing: true,\n      };\n\n      dispatchEvent(fakeElement as any, eventType, customArgs);\n\n      expect(fakeElement.dispatchEvent.called).to.equal(true);\n      const event = fakeElement.dispatchEvent.lastCall.args[0];\n      expect(event).to.be.instanceof(CustomEvent);\n      expect(event.bubbles).to.equal(true);\n      expect(event.cancelable).to.equal(true);\n      expect(event.detail).to.equal(customArgs);\n    });\n  });\n\n  describe('cloneObject', () => {\n    it('deeply clones a given object', () => {\n      const object = {\n        levelOne: {\n          id: 1,\n          levelTwo: {\n            id: 2,\n            levelThree: {\n              id: 3,\n              levelFour: {\n                id: 4,\n              },\n            },\n          },\n        },\n      };\n\n      const output = cloneObject(object);\n\n      expect(output).to.not.equal(object);\n      expect(output).to.deep.equal(object);\n    });\n  });\n\n  describe('diff', () => {\n    it('returns an array of keys present on the first but missing on the second object', () => {\n      const obj1 = {\n        foo: 'bar',\n        baz: 'foo',\n      };\n      const obj2 = {\n        foo: 'bar',\n      };\n\n      const output = diff(obj1, obj2);\n\n      expect(output).to.deep.equal(['baz']);\n    });\n  });\n\n  describe('_parseCustomProperties', () => {\n    describe('when custom properties are valid json', () => {\n      it('returns the properties as object', () => {\n        const customProperties = '{\"description\": \"foo\", \"bar\": \"foo\"}';\n        const result = { description: 'foo', bar: 'foo' };\n\n        const value = parseCustomProperties(customProperties);\n        expect(value).to.deep.equal(result);\n      });\n    });\n    describe('when custom properties are undefined', () => {\n      it('returns an empty object', () => {\n        const customProperties = undefined;\n        const result = {};\n\n        const value = parseCustomProperties(customProperties);\n        expect(value).to.deep.equal(result);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/scripts/reducers/choices.test.ts",
    "content": "import { expect } from 'chai';\nimport choices from '../../../src/scripts/reducers/choices';\nimport { cloneObject } from '../../../src/scripts/lib/utils';\nimport { ChoiceFull } from '../../../src/scripts/interfaces/choice-full';\nimport { ActionType } from '../../../src';\nimport { StateUpdate } from '../../../src/scripts/interfaces/store';\n\ndescribe('reducers/choices', () => {\n  describe('when choices do not exist', () => {\n    describe('ADD_CHOICE', () => {\n      const choice: ChoiceFull = {\n        highlighted: false,\n        value: 'test',\n        label: 'test',\n        id: 1,\n        elementId: '1',\n        group: null,\n        active: false,\n        disabled: false,\n        placeholder: true,\n        selected: false,\n        customProperties: {\n          test: true,\n        },\n        score: 0,\n        rank: 0,\n      };\n\n      describe('passing expected values', () => {\n        it('adds choice', () => {\n          const expectedResponse: StateUpdate<ChoiceFull[]> = {\n            update: true,\n            state: [choice],\n          };\n\n          const actualResponse = choices([], {\n            type: ActionType.ADD_CHOICE,\n            choice: cloneObject(choice),\n          });\n\n          expect(actualResponse).to.deep.equal(expectedResponse);\n        });\n      });\n\n      describe('fallback values', () => {\n        describe('passing no placeholder value', () => {\n          it('adds choice with placeholder set to false', () => {\n            const item = Object.assign(cloneObject(choice), {\n              placeholder: false,\n            });\n            const expectedResponse: StateUpdate<ChoiceFull[]> = {\n              update: true,\n              state: [item],\n            };\n\n            const actualResponse = choices([], {\n              type: ActionType.ADD_CHOICE,\n              choice: cloneObject(item),\n            });\n\n            expect(actualResponse).to.deep.equal(expectedResponse);\n          });\n        });\n      });\n    });\n  });\n\n  describe('when choices exist', () => {\n    let state: ChoiceFull[];\n\n    beforeEach(() => {\n      state = [\n        {\n          id: 1,\n          elementId: 'choices-test-1',\n          group: null,\n          value: 'Choice 1',\n          label: 'Choice 1',\n          disabled: false,\n          selected: false,\n          active: false,\n          score: 9999,\n          rank: 9999,\n          customProperties: {},\n          placeholder: false,\n          highlighted: false,\n        },\n        {\n          id: 2,\n          elementId: 'choices-test-2',\n          group: null,\n          value: 'Choice 2',\n          label: 'Choice 2',\n          disabled: false,\n          selected: true,\n          active: false,\n          score: 9999,\n          rank: 9999,\n          customProperties: {},\n          placeholder: false,\n          highlighted: false,\n        },\n      ];\n    });\n\n    describe('FILTER_CHOICES', () => {\n      it('sets active flag based on whether choice is in passed results', () => {\n        const id = 1;\n        const score = 10;\n        const rank = 10;\n        const active = true;\n\n        const expectedResponse = {\n          ...state[0],\n          active,\n          score,\n          rank,\n        } as ChoiceFull;\n\n        const actualResponse = choices(cloneObject(state), {\n          type: ActionType.FILTER_CHOICES,\n          results: [\n            {\n              item: { id } as ChoiceFull,\n              score,\n              rank,\n            },\n          ],\n        }).state.find((choice) => choice.id === id);\n\n        expect(actualResponse).to.deep.equal(expectedResponse);\n      });\n    });\n\n    describe('ACTIVATE_CHOICES', () => {\n      it('sets active flag to passed value', () => {\n        const expectedResponse: StateUpdate<ChoiceFull[]> = {\n          update: true,\n          state: [\n            {\n              ...state[0],\n              active: true,\n            },\n            {\n              ...state[1],\n              active: true,\n            },\n          ],\n        };\n\n        const actualResponse = choices(cloneObject(state), {\n          type: ActionType.ACTIVATE_CHOICES,\n          active: true,\n        });\n\n        expect(actualResponse).to.deep.equal(expectedResponse);\n      });\n    });\n\n    describe('ADD_ITEM', () => {\n      describe('when action has a choice id', () => {\n        it('disables choice corresponding with id', () => {\n          const expectedResponse: StateUpdate<ChoiceFull[]> = {\n            update: true,\n            state: [\n              {\n                ...state[0],\n              },\n              {\n                ...state[1],\n                selected: true,\n              },\n            ],\n          };\n\n          const actualResponse = choices(cloneObject(state), {\n            type: ActionType.ADD_ITEM,\n            item: cloneObject(state[1]),\n          });\n\n          expect(actualResponse).to.deep.equal(expectedResponse);\n        });\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/scripts/reducers/groups.test.ts",
    "content": "import { expect } from 'chai';\nimport groups from '../../../src/scripts/reducers/groups';\nimport { cloneObject } from '../../../src/scripts/lib/utils';\nimport { GroupFull } from '../../../src/scripts/interfaces/group-full';\nimport { ActionType } from '../../../src';\nimport { StateUpdate } from '../../../src/scripts/interfaces/store';\n\ndescribe('reducers/groups', () => {\n  describe('when groups do not exist', () => {\n    describe('ADD_GROUP', () => {\n      it('adds group', () => {\n        const group: GroupFull = {\n          active: true,\n          disabled: false,\n          id: 1,\n          label: 'Group one',\n          choices: [],\n        };\n\n        const expectedResponse: StateUpdate<GroupFull[]> = {\n          update: true,\n          state: [group],\n        };\n\n        const actualResponse = groups([], {\n          type: ActionType.ADD_GROUP,\n          group: cloneObject(group),\n        });\n\n        expect(actualResponse).to.deep.equal(expectedResponse);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/scripts/reducers/items.test.ts",
    "content": "import { expect } from 'chai';\nimport items from '../../../src/scripts/reducers/items';\nimport { RemoveItemAction } from '../../../src/scripts/actions/items';\nimport { cloneObject } from '../../../src/scripts/lib/utils';\nimport { ChoiceFull } from '../../../src/scripts/interfaces/choice-full';\nimport { ActionType } from '../../../src';\nimport { StateUpdate } from '../../../src/scripts/interfaces/store';\n\ndescribe('reducers/items', () => {\n  describe('when items do not exist', () => {\n    describe('ADD_ITEM', () => {\n      const choice: ChoiceFull = {\n        value: 'Item one',\n        label: 'Item one',\n        id: 1234,\n        group: null,\n        score: 0,\n        rank: 0,\n        customProperties: {\n          property: 'value',\n        },\n        placeholder: true,\n        active: true,\n        disabled: false,\n        selected: true,\n        highlighted: false,\n      };\n\n      describe('passing expected values', () => {\n        let actualResponse: ChoiceFull[];\n\n        beforeEach(() => {\n          actualResponse = items([], {\n            type: ActionType.ADD_ITEM,\n            item: cloneObject(choice),\n          }).state;\n        });\n\n        it('adds item', () => {\n          const expectedResponse = [choice];\n\n          expect(actualResponse).to.deep.equal(expectedResponse);\n        });\n\n        it('unhighlights all highlighted items', () => {\n          actualResponse.forEach((item) => {\n            expect(item.highlighted).to.equal(false);\n          });\n        });\n      });\n\n      describe('fallback values', () => {\n        describe('passing no placeholder value', () => {\n          const item = Object.assign(cloneObject(choice), {\n            placeholder: false,\n          });\n          it('adds item with placeholder set to false', () => {\n            const expectedResponse: StateUpdate<ChoiceFull[]> = {\n              update: true,\n              state: [item],\n            };\n\n            const actualResponse = items([], {\n              type: ActionType.ADD_ITEM,\n              item: cloneObject(item),\n            });\n\n            expect(actualResponse).to.deep.equal(expectedResponse);\n          });\n        });\n      });\n    });\n  });\n\n  describe('when items exist', () => {\n    let state: ChoiceFull[];\n\n    beforeEach(() => {\n      state = [\n        {\n          id: 1,\n          group: null,\n          score: 0,\n          rank: 0,\n          value: 'Item one',\n          label: 'Item one',\n          active: false,\n          highlighted: false,\n          customProperties: {},\n          placeholder: false,\n          disabled: false,\n          selected: false,\n        },\n        {\n          id: 2,\n          group: null,\n          score: 0,\n          rank: 0,\n          value: 'Item one',\n          label: 'Item one',\n          active: true,\n          highlighted: false,\n          customProperties: {},\n          placeholder: false,\n          disabled: false,\n          selected: false,\n        },\n      ];\n    });\n\n    describe('REMOVE_ITEM', () => {\n      it('sets an item to be inactive based on passed ID', () => {\n        const expectedResponse: StateUpdate<ChoiceFull[]> = {\n          update: true,\n          state: [\n            {\n              ...state[0],\n            },\n          ],\n        };\n\n        const actualResponse = items(cloneObject(state), {\n          type: ActionType.REMOVE_ITEM,\n          item: cloneObject(state[1]),\n        } as RemoveItemAction);\n\n        expect(actualResponse).to.deep.equal(expectedResponse);\n      });\n    });\n\n    describe('REMOVE_CHOICE', () => {\n      it('the item is removed', () => {\n        const choice = state[0];\n        const expectedResponse: StateUpdate<ChoiceFull[]> = {\n          update: true,\n          state: state.filter((s) => s.id !== choice.id),\n        };\n\n        const actualResponse = items(cloneObject(state), {\n          type: ActionType.REMOVE_CHOICE,\n          choice: cloneObject(choice),\n        });\n\n        expect(actualResponse).to.deep.equal(expectedResponse);\n      });\n    });\n\n    describe('HIGHLIGHT_ITEM', () => {\n      it('sets an item to be inactive based on passed ID', () => {\n        const expectedResponse: StateUpdate<ChoiceFull[]> = {\n          update: true,\n          state: [\n            {\n              ...state[0],\n            },\n            {\n              ...state[1],\n              highlighted: true,\n            },\n          ],\n        };\n\n        const actualResponse = items(cloneObject(state), {\n          type: ActionType.HIGHLIGHT_ITEM,\n          item: cloneObject(state[1]),\n          highlighted: true,\n        });\n\n        expect(actualResponse).to.deep.equal(expectedResponse);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/scripts/search/index.test.ts",
    "content": "import { expect } from 'chai';\nimport { beforeEach } from 'vitest';\nimport { DEFAULT_CONFIG } from '../../../src';\nimport { cloneObject } from '../../../src/scripts/lib/utils';\nimport { SearchByFuse } from '../../../src/scripts/search/fuse';\nimport { SearchByKMP } from '../../../src/scripts/search/kmp';\nimport { SearchByPrefixFilter } from '../../../src/scripts/search/prefix-filter';\n\nexport interface SearchableShape {\n  label: string;\n  value: string;\n}\n\ndescribe('search', () => {\n  const options = DEFAULT_CONFIG;\n  const haystack: SearchableShape[] = [];\n  Array.from(Array(10).keys()).forEach((i) =>\n    haystack.push({\n      label: `label ${i}`,\n      value: `value ${i}`,\n    }),\n  );\n\n  describe('fuse-full', () => {\n    let searcher: SearchByFuse<SearchableShape>;\n\n    beforeEach(() => {\n      process.env.CHOICES_SEARCH_FUSE = 'full';\n      searcher = new SearchByFuse<SearchableShape>(options);\n      searcher.index(haystack);\n    });\n    it('empty result', () => {\n      const results = searcher.search('');\n      expect(results.length).eq(0);\n    });\n    it('label prefix', () => {\n      const results = searcher.search('label');\n      expect(results.length).eq(haystack.length);\n    });\n    it('label suffix', () => {\n      const results = searcher.search(`${haystack.length - 1}`);\n      expect(results.length).eq(1);\n    });\n\n    it('search order', () => {\n      const results = searcher.search('label');\n\n      expect(results.length).eq(haystack.length);\n      haystack.forEach((value, index) => {\n        expect(results[index].item.value).eq(value.value);\n      });\n    });\n\n    it('search order - custom sortFn', () => {\n      const opts = cloneObject(options);\n      opts.fuseOptions.sortFn = (a, b) => {\n        if (a.score === b.score) {\n          return a.idx < b.idx ? 1 : -1;\n        }\n\n        return a.score < b.score ? 1 : -1;\n      };\n\n      searcher = new SearchByFuse<SearchableShape>(opts);\n      searcher.index(haystack);\n      const results = searcher.search('label');\n\n      expect(results.length).eq(haystack.length);\n      haystack.reverse().forEach((value, index) => {\n        expect(results[index].item.value).eq(value.value);\n      });\n    });\n  });\n\n  describe('fuse-basic', () => {\n    let searcher: SearchByFuse<SearchableShape>;\n    beforeEach(() => {\n      process.env.CHOICES_SEARCH_FUSE = 'basic';\n      searcher = new SearchByFuse<SearchableShape>(options);\n      searcher.index(haystack);\n    });\n    it('empty result', () => {\n      const results = searcher.search('');\n      expect(results.length).eq(0);\n    });\n    it('label prefix', () => {\n      const results = searcher.search('label');\n      expect(results.length).eq(haystack.length);\n    });\n    it('label suffix', () => {\n      const results = searcher.search(`${haystack.length - 1}`);\n      expect(results.length).eq(1);\n    });\n    it('search order', () => {\n      const results = searcher.search('label');\n\n      expect(results.length).eq(haystack.length);\n      haystack.forEach((value, index) => {\n        expect(results[index].item.value).eq(value.value);\n      });\n    });\n  });\n\n  describe('kmp', () => {\n    let searcher: SearchByKMP<SearchableShape>;\n    beforeEach(() => {\n      process.env.CHOICES_SEARCH_KMP = '1';\n      searcher = new SearchByKMP<SearchableShape>(options);\n      searcher.index(haystack);\n    });\n    it('empty result', () => {\n      const results = searcher.search('');\n      expect(results.length).eq(0);\n    });\n    it('label prefix', () => {\n      const results = searcher.search('label');\n      expect(results.length).eq(haystack.length);\n    });\n    it('label suffix', () => {\n      const results = searcher.search(`${haystack.length - 1}`);\n      expect(results.length).eq(1);\n    });\n    it('search order', () => {\n      const results = searcher.search('label');\n\n      expect(results.length).eq(haystack.length);\n      haystack.forEach((value, index) => {\n        expect(results[index].item.value).eq(value.value);\n      });\n    });\n  });\n\n  describe('prefix-filter', () => {\n    let searcher: SearchByPrefixFilter<SearchableShape>;\n    beforeEach(() => {\n      process.env.CHOICES_SEARCH_FUSE = undefined;\n      searcher = new SearchByPrefixFilter<SearchableShape>(options);\n      searcher.index(haystack);\n    });\n    it('empty result', () => {\n      const results = searcher.search('');\n      expect(results.length).eq(0);\n    });\n    it('label prefix', () => {\n      const results = searcher.search('label');\n      expect(results.length).eq(haystack.length);\n    });\n    it('label suffix', () => {\n      const results = searcher.search(`${haystack.length - 1}`);\n      expect(results.length).eq(0);\n    });\n    it('search order', () => {\n      const results = searcher.search('label');\n\n      expect(results.length).eq(haystack.length);\n      haystack.forEach((value, index) => {\n        expect(results[index].item.value).eq(value.value);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/scripts/store/store.test.ts",
    "content": "import { expect } from 'chai';\nimport sinon from 'sinon';\nimport { beforeEach } from 'vitest';\nimport Store from '../../../src/scripts/store/store';\n// eslint-disable-next-line import/no-named-default\nimport { ActionType, State, default as Choices } from '../../../src';\nimport { cloneObject } from '../../../src/scripts/lib/utils';\nimport { AnyAction, StoreListener } from '../../../src/scripts/interfaces/store';\nimport { Options } from '../../../src/scripts/interfaces/options';\n\nfunction shimStore() {\n  return new Store(Choices.defaults.allOptions);\n}\n\ndescribe('reducers/store', () => {\n  let instance: Store<Options>;\n  let subscribeStub: sinon.SinonStub<[listener: StoreListener], Store<Options>>;\n  let dispatchStub: sinon.SinonStub<[action: AnyAction], void>;\n  let getStateStub: sinon.SinonStub<any[], State>;\n  let emptyState: State;\n  let state: State;\n\n  beforeEach(() => {\n    instance = shimStore();\n    subscribeStub = sinon.stub(instance, 'subscribe');\n    dispatchStub = sinon.stub(instance, 'dispatch');\n    getStateStub = sinon.stub(instance, 'state');\n    emptyState = instance.defaultState;\n    state = {\n      items: [\n        {\n          id: 1,\n          group: null,\n          value: 'Item one',\n          label: 'Item one',\n          active: false,\n          highlighted: false,\n          customProperties: {},\n          placeholder: false,\n          disabled: false,\n          selected: false,\n          score: 0,\n          rank: 0,\n        },\n        {\n          id: 2,\n          group: null,\n          value: 'Item two',\n          label: 'Item two',\n          active: true,\n          highlighted: false,\n          customProperties: {},\n          placeholder: false,\n          disabled: false,\n          selected: false,\n          score: 0,\n          rank: 0,\n        },\n        {\n          id: 3,\n          group: null,\n          value: 'Item three',\n          label: 'Item three',\n          active: true,\n          highlighted: true,\n          customProperties: {},\n          placeholder: false,\n          disabled: false,\n          selected: false,\n          score: 0,\n          rank: 0,\n        },\n      ],\n      choices: [\n        {\n          id: 1,\n          elementId: 'choices-test-1',\n          group: null,\n          value: 'Choice 1',\n          label: 'Choice 1',\n          disabled: false,\n          selected: false,\n          active: true,\n          score: 9999,\n          rank: 9999,\n          customProperties: {},\n          placeholder: false,\n          highlighted: false,\n        },\n        {\n          id: 2,\n          elementId: 'choices-test-2',\n          group: null,\n          value: 'Choice 2',\n          label: 'Choice 2',\n          disabled: false,\n          selected: true,\n          active: false,\n          score: 9999,\n          rank: 9998,\n          customProperties: {},\n          placeholder: false,\n          highlighted: false,\n        },\n      ],\n      groups: [\n        {\n          id: 1,\n          label: 'Group one',\n          active: true,\n          disabled: false,\n          choices: [],\n        },\n        {\n          id: 2,\n          label: 'Group two',\n          active: true,\n          disabled: false,\n          choices: [],\n        },\n      ],\n    };\n  });\n\n  afterEach(() => {\n    subscribeStub.restore();\n    dispatchStub.restore();\n    getStateStub.restore();\n  });\n\n  describe('constructor', () => {\n    it('creates redux-like store', () => {\n      expect(instance).to.contain.keys(['_state', '_listeners', '_txn']);\n    });\n  });\n\n  describe('subscribe', () => {\n    it('wraps redux-like subscribe method', () => {\n      const onChange = (): void => {};\n      expect(subscribeStub.callCount).to.equal(0);\n      instance.subscribe(onChange);\n      expect(subscribeStub.callCount).to.equal(1);\n      expect(subscribeStub.firstCall.args[0]).to.equal(onChange);\n    });\n  });\n\n  describe('dispatch', () => {\n    it('wraps redux-like dispatch method', () => {\n      const action: AnyAction = { type: ActionType.CLEAR_CHOICES };\n      expect(dispatchStub.callCount).to.equal(0);\n      instance.dispatch(action);\n      expect(dispatchStub.callCount).to.equal(1);\n      expect(dispatchStub.firstCall.args[0]).to.equal(action);\n    });\n  });\n\n  describe('state getter', () => {\n    it('returns state', () => {\n      getStateStub.value(cloneObject(emptyState));\n\n      expect(instance.state).to.deep.equal(emptyState);\n    });\n  });\n\n  describe('txn', () => {\n    let listenerStub: sinon.SinonStub;\n\n    beforeEach(() => {\n      subscribeStub.restore();\n      dispatchStub.restore();\n      getStateStub.restore();\n\n      instance._state = cloneObject(state);\n      listenerStub = sinon.stub();\n      instance.subscribe(listenerStub);\n    });\n\n    it('coalesce listener events', () => {\n      const emptyChoicesState = cloneObject(state);\n      emptyChoicesState.choices = [];\n      emptyChoicesState.groups = [];\n\n      instance.withTxn(() => {\n        const action: AnyAction = { type: ActionType.CLEAR_CHOICES };\n        instance.dispatch(action);\n        instance.dispatch(action);\n      });\n\n      expect(listenerStub.callCount).eq(1);\n      expect(instance.state).to.deep.equal(emptyChoicesState);\n    });\n\n    it('coalesce listener events with reset', () => {\n      instance.withTxn(() => {\n        const action: AnyAction = { type: ActionType.CLEAR_CHOICES };\n        instance.dispatch(action);\n        instance.dispatch(action);\n        instance.reset();\n      });\n\n      expect(listenerStub.callCount).eq(1);\n      expect(instance.state).to.deep.equal(emptyState);\n    });\n  });\n\n  describe('without txn', () => {\n    let listenerStub: sinon.SinonStub;\n\n    beforeEach(() => {\n      subscribeStub.restore();\n      dispatchStub.restore();\n      getStateStub.restore();\n\n      instance._state = cloneObject(state);\n      listenerStub = sinon.stub();\n      instance.subscribe(listenerStub);\n    });\n\n    it('multiple listener events', () => {\n      const emptyChoicesState = cloneObject(state);\n      emptyChoicesState.choices = [];\n      emptyChoicesState.groups = [];\n\n      const action: AnyAction = { type: ActionType.CLEAR_CHOICES };\n      instance.dispatch(action);\n      instance.dispatch(action);\n\n      expect(listenerStub.callCount).eq(2);\n      expect(instance.state).to.deep.equal(emptyChoicesState);\n    });\n\n    it('multiple listener events with reset', () => {\n      const action: AnyAction = { type: ActionType.CLEAR_CHOICES };\n      instance.dispatch(action);\n      instance.dispatch(action);\n      instance.reset();\n\n      expect(listenerStub.callCount).eq(3);\n      expect(instance.state).to.deep.equal(emptyState);\n    });\n  });\n\n  describe('store selectors', () => {\n    beforeEach(() => {\n      getStateStub.value(cloneObject(state));\n    });\n\n    describe('items getter', () => {\n      it('returns items', () => {\n        const expectedResponse = state.items;\n        expect(instance.items).to.deep.equal(expectedResponse);\n      });\n    });\n\n    describe('highlightedActiveItems getter', () => {\n      it('returns items that are active and highlighted', () => {\n        const expectedResponse = state.items.filter((item) => item.highlighted && item.active);\n        expect(instance.highlightedActiveItems).to.deep.equal(expectedResponse);\n      });\n    });\n\n    describe('choices getter', () => {\n      it('returns choices', () => {\n        const expectedResponse = state.choices;\n        expect(instance.choices).to.deep.equal(expectedResponse);\n      });\n    });\n\n    describe('activeChoices getter', () => {\n      it('returns choices that are active', () => {\n        const expectedResponse = state.choices.filter((choice) => choice.active);\n        expect(instance.activeChoices).to.deep.equal(expectedResponse);\n      });\n    });\n\n    describe('searchableChoices getter', () => {\n      it('returns choices that are not placeholders and are selectable', () => {\n        const expectedResponse = state.choices.filter((choice) => !choice.disabled && !choice.placeholder);\n        expect(instance.searchableChoices).to.deep.equal(expectedResponse);\n      });\n\n      it('includes disabled choices when searchDisabledChoices is true', () => {\n        const configWithDisabled = { ...Choices.defaults.allOptions, searchDisabledChoices: true };\n        const instanceWithConfig = new Store(configWithDisabled);\n        instanceWithConfig._state = state;\n\n        const expectedResponse = state.choices.filter((choice) => !choice.placeholder);\n        expect(instanceWithConfig.searchableChoices).to.deep.equal(expectedResponse);\n      });\n    });\n\n    describe('getChoiceById', () => {\n      describe('passing id', () => {\n        it('returns active choice by passed id', () => {\n          const id: number = 1;\n          const expectedResponse = state.choices.find((choice) => choice.id === id);\n          const actualResponse = instance.getChoiceById(id);\n          expect(actualResponse).to.deep.equal(expectedResponse);\n        });\n      });\n    });\n\n    describe('groups getter', () => {\n      it('returns groups', () => {\n        const expectedResponse = state.groups;\n        expect(instance.groups).to.deep.equal(expectedResponse);\n      });\n    });\n\n    describe('activeGroups getter', () => {\n      it('returns active groups', () => {\n        const expectedResponse = state.groups.filter((group) => group.active);\n        expect(instance.activeGroups).to.deep.equal(expectedResponse);\n      });\n    });\n\n    describe('getGroupById', () => {\n      it('returns group by id', () => {\n        const id = 1;\n        const expectedResponse = state.groups.find((group) => group.id === id);\n        const actualResponse = instance.getGroupById(id);\n        expect(actualResponse).to.deep.equal(expectedResponse);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/scripts/templates.test.ts",
    "content": "import { expect } from 'chai';\n// eslint-disable-next-line import/no-named-default\nimport { default as _templates } from '../../src/scripts/templates';\nimport { strToEl, getClassNames } from '../../src/scripts/lib/utils';\nimport { DEFAULT_CLASSNAMES, DEFAULT_CONFIG, Options, ClassNames } from '../../src';\nimport { NoticeTypes, Templates as TemplatesInterface } from '../../src/scripts/interfaces/templates';\n\n/**\n * @param {HTMLElement} element1\n * @param {HTMLElement} element2\n */\nfunction expectEqualElements(element1, element2): void {\n  expect(element1.tagName).to.equal(element2.tagName);\n  expect(Object.keys(element1.dataset)).to.have.members(Object.keys(element2.dataset));\n  expect(element1.classList).to.include(element2.classList);\n  // compare attributes values\n  for (const attribute of Object.values(element1.attributes)) {\n    expect(element1.getAttribute(attribute)).to.equal(element2.getAttribute(attribute));\n  }\n  expect(element1.attributes.length).to.equal(element2.attributes.length);\n}\n\nfunction createOptionsWithPartialClasses(classNames: Partial<ClassNames>, options: Partial<Options> = {}): Options {\n  return {\n    ...DEFAULT_CONFIG,\n    ...options,\n    classNames: {\n      ...DEFAULT_CLASSNAMES,\n      ...classNames,\n    },\n  };\n}\n\nfunction shimTemplates(element: string): TemplatesInterface {\n  const fauxChoices = {\n    _docRoot: document.createElement('body'),\n    passedElement: {\n      element: document.createElement(element),\n    },\n  };\n\n  const templating = {};\n  Object.keys(_templates).forEach((name) => {\n    templating[name] = _templates[name].bind(fauxChoices);\n  });\n\n  return templating as TemplatesInterface;\n}\n\ndescribe('templates', () => {\n  describe('containerOuter', () => {\n    const options = createOptionsWithPartialClasses({\n      containerOuter: 'class-1',\n    });\n    const direction = 'rtl';\n\n    describe('select element', () => {\n      const templates = shimTemplates('select');\n      describe('search enabled', () => {\n        it('returns expected html', () => {\n          const isSelectElement = true;\n          const isSelectOneElement = false;\n          const searchEnabled = true;\n          const passedElementType = 'select-multiple';\n          const labelId = '';\n\n          const expectedOutput = strToEl(`\n            <div\n              class=\"${getClassNames(options.classNames.containerOuter).join(' ')}\"\n              data-type=\"${passedElementType}\"\n              role=\"combobox\"\n              aria-autocomplete=\"list\"\n              aria-haspopup=\"true\"\n              aria-expanded=\"false\"\n              dir=\"${direction}\"\n              >\n            </div>\n          `);\n          const actualOutput = templates.containerOuter(\n            options,\n            direction,\n            isSelectElement,\n            isSelectOneElement,\n            searchEnabled,\n            passedElementType,\n            labelId,\n          );\n          expectEqualElements(actualOutput, expectedOutput);\n        });\n      });\n\n      describe('with label id for a11y', () => {\n        it('returns expected html', () => {\n          const isSelectElement = true;\n          const isSelectOneElement = true;\n          const searchEnabled = false;\n          const passedElementType = 'select-one';\n          const labelId = 'testLabelId';\n\n          const expectedOutput = strToEl(`\n            <div\n              class=\"${options.classNames.containerOuter}\"\n              data-type=\"${passedElementType}\"\n              role=\"listbox\"\n              tabindex=\"0\"\n              aria-haspopup=\"true\"\n              aria-expanded=\"false\"\n              aria-labelledby=\"${labelId}\"\n              dir=\"${direction}\"\n              >\n            </div>\n          `);\n          const actualOutput = templates.containerOuter(\n            options,\n            direction,\n            isSelectElement,\n            isSelectOneElement,\n            searchEnabled,\n            passedElementType,\n            labelId,\n          );\n          expectEqualElements(actualOutput, expectedOutput);\n        });\n      });\n\n      describe('search disabled', () => {\n        it('returns expected html', () => {\n          const isSelectElement = true;\n          const isSelectOneElement = false;\n          const searchEnabled = false;\n          const passedElementType = 'select-multiple';\n          const labelId = '';\n\n          const expectedOutput = strToEl(`\n            <div\n              class=\"${getClassNames(options.classNames.containerOuter).join(' ')}\"\n              data-type=\"${passedElementType}\"\n              role=\"listbox\"\n              aria-haspopup=\"true\"\n              aria-expanded=\"false\"\n              dir=\"${direction}\"\n              >\n            </div>\n          `);\n          const actualOutput = templates.containerOuter(\n            options,\n            direction,\n            isSelectElement,\n            isSelectOneElement,\n            searchEnabled,\n            passedElementType,\n            labelId,\n          );\n\n          expectEqualElements(actualOutput, expectedOutput);\n        });\n      });\n\n      describe('select one element', () => {\n        it('returns expected html', () => {\n          const isSelectElement = true;\n          const isSelectOneElement = true;\n          const searchEnabled = false;\n          const passedElementType = 'select-one';\n          const labelId = '';\n\n          const expectedOutput = strToEl(`\n            <div\n              class=\"${getClassNames(options.classNames.containerOuter).join(' ')}\"\n              data-type=\"${passedElementType}\"\n              role=\"listbox\"\n              tabindex=\"0\"\n              aria-haspopup=\"true\"\n              aria-expanded=\"false\"\n              dir=\"${direction}\"\n              >\n            </div>\n          `);\n          const actualOutput = templates.containerOuter(\n            options,\n            direction,\n            isSelectElement,\n            isSelectOneElement,\n            searchEnabled,\n            passedElementType,\n            labelId,\n          );\n\n          expectEqualElements(actualOutput, expectedOutput);\n        });\n      });\n    });\n\n    describe('non select element', () => {\n      const templates = shimTemplates('input');\n      it('returns expected html', () => {\n        const isSelectElement = false;\n        const isSelectOneElement = false;\n        const searchEnabled = false;\n        const passedElementType = 'text';\n        const labelId = '';\n\n        const expectedOutput = strToEl(`\n          <div\n            class=\"${getClassNames(options.classNames.containerOuter).join(' ')}\"\n            data-type=\"${passedElementType}\"\n            dir=\"${direction}\"\n            >\n          </div>\n        `);\n        const actualOutput = templates.containerOuter(\n          options,\n          direction,\n          isSelectElement,\n          isSelectOneElement,\n          searchEnabled,\n          passedElementType,\n          labelId,\n        );\n\n        expectEqualElements(actualOutput, expectedOutput);\n      });\n    });\n  });\n\n  describe('containerInner', () => {\n    const templates = shimTemplates('select');\n    it('returns expected html', () => {\n      const innerOptions = createOptionsWithPartialClasses({\n        containerInner: 'class-1',\n      });\n      const expectedOutput = strToEl(\n        `<div class=\"${getClassNames(innerOptions.classNames.containerInner).join(' ')}\"></div>`,\n      );\n      const actualOutput = templates.containerInner(innerOptions);\n\n      expectEqualElements(actualOutput, expectedOutput);\n    });\n  });\n\n  describe('itemList', () => {\n    const templates = shimTemplates('select');\n    const itemOptions = createOptionsWithPartialClasses({\n      list: 'class-1',\n      listSingle: 'class-2',\n      listItems: 'class-3',\n    });\n\n    describe('select one element', () => {\n      it('returns expected html', () => {\n        const expectedOutput = strToEl(\n          `<div class=\"${getClassNames(itemOptions.classNames.list).join(' ')} ${getClassNames(itemOptions.classNames.listSingle).join(' ')}\"></div>`,\n        );\n        const actualOutput = templates.itemList(itemOptions, true);\n\n        expectEqualElements(actualOutput, expectedOutput);\n      });\n    });\n\n    describe('non select one element', () => {\n      it('returns expected html', () => {\n        const expectedOutput = strToEl(\n          `<div class=\"${getClassNames(itemOptions.classNames.list).join(' ')} ${getClassNames(itemOptions.classNames.listItems).join(' ')}\"></div>`,\n        );\n        const actualOutput = templates.itemList(itemOptions, false);\n\n        expectEqualElements(actualOutput, expectedOutput);\n      });\n    });\n  });\n\n  describe('placeholder', () => {\n    const templates = shimTemplates('select');\n    it('returns expected html', () => {\n      const placeholderOptions = createOptionsWithPartialClasses({\n        placeholder: 'class-1',\n      });\n      const value = 'test';\n      const expectedOutput = strToEl(`\n        <div class=\"${getClassNames(placeholderOptions.classNames.placeholder).join(' ')}\">${value}</div>`);\n      const actualOutput = templates.placeholder(placeholderOptions, value);\n\n      expectEqualElements(actualOutput, expectedOutput);\n    });\n  });\n\n  describe('choiceList', () => {\n    const choiceListOptions = createOptionsWithPartialClasses({\n      list: 'class-1',\n    });\n\n    describe('select one element', () => {\n      const templates = shimTemplates('select');\n      it('returns expected html', () => {\n        const expectedOutput = strToEl(`\n          <div\n            class=\"${getClassNames(choiceListOptions.classNames.list).join(' ')}\"\n            role=\"listbox\"\n            >\n          </div>\n        `);\n        const actualOutput = templates.choiceList(choiceListOptions, true);\n\n        expectEqualElements(actualOutput, expectedOutput);\n      });\n    });\n\n    describe('non select one element', () => {\n      const templates = shimTemplates('input');\n      it('returns expected html', () => {\n        const expectedOutput = strToEl(`\n          <div\n            class=\"${getClassNames(choiceListOptions.classNames.list).join(' ')}\"\n            role=\"listbox\"\n            aria-multiselectable=\"true\"\n            >\n          </div>\n        `);\n        const actualOutput = templates.choiceList(choiceListOptions, false);\n\n        expectEqualElements(actualOutput, expectedOutput);\n      });\n    });\n  });\n\n  describe('choiceGroup', () => {\n    const templates = shimTemplates('select');\n    const groupOptions = createOptionsWithPartialClasses({\n      group: 'class-1',\n      groupHeading: 'class-2',\n      itemDisabled: 'class-3',\n    });\n\n    let data;\n\n    beforeEach(() => {\n      data = {\n        id: 1,\n        value: 'test',\n        disabled: false,\n      };\n    });\n\n    describe('enabled state', () => {\n      it('returns expected html', () => {\n        const expectedOutput = strToEl(`\n          <div\n          class=\"${getClassNames(groupOptions.classNames.group).join(' ')}\"\n            data-group\n            data-id=\"${data.id}\"\n            data-value=\"${data.value}\"\n            role=\"group\"\n            >\n            <div class=\"${getClassNames(groupOptions.classNames.groupHeading).join(' ')}\">${data.value}</div>\n          </div>\n        `);\n        const actualOutput = templates.choiceGroup(groupOptions, data);\n\n        expectEqualElements(actualOutput, expectedOutput);\n      });\n    });\n\n    describe('disabled state', () => {\n      beforeEach(() => {\n        data = {\n          ...data,\n          disabled: true,\n        };\n      });\n\n      it('returns expected html', () => {\n        const expectedOutput = strToEl(`\n          <div\n            class=\"${getClassNames(groupOptions.classNames.group).join(' ')} ${getClassNames(groupOptions.classNames.itemDisabled).join(' ')}\"\n            data-group\n            data-id=\"${data.id}\"\n            data-value=\"${data.value}\"\n            role=\"group\"\n            aria-disabled=\"true\"\n            >\n            <div class=\"${getClassNames(groupOptions.classNames.groupHeading).join(' ')}\">${data.value}</div>\n          </div>\n        `);\n        const actualOutput = templates.choiceGroup(groupOptions, data);\n\n        expectEqualElements(actualOutput, expectedOutput);\n      });\n    });\n  });\n\n  describe('choice', () => {\n    const templates = shimTemplates('select');\n    const choiceOptions = createOptionsWithPartialClasses({\n      item: 'class-1',\n      itemChoice: 'class-2',\n      itemDisabled: 'class-3',\n      itemSelectable: 'class-4',\n      placeholder: 'class-5',\n      selectedState: 'class-6',\n    });\n\n    const itemSelectText = 'test 6';\n\n    let data;\n\n    beforeEach(() => {\n      data = {\n        id: 1,\n        group: null,\n        disabled: false,\n        elementId: 'test',\n        label: 'test',\n        value: 'test',\n        selected: false,\n      };\n    });\n\n    describe('enabled state', () => {\n      it('returns expected html', () => {\n        const expectedOutput = strToEl(`\n          <div\n            class=\"${getClassNames(choiceOptions.classNames.item).join(' ')} ${getClassNames(\n              choiceOptions.classNames.itemChoice,\n            ).join(' ')} ${getClassNames(choiceOptions.classNames.itemSelectable).join(' ')}\"\n            data-select-text=\"${itemSelectText}\"\n            data-choice\n            data-id=\"${data.id}\"\n            data-value=\"${data.value}\"\n            data-choice-selectable\n            aria-selected=\"false\"\n            id=\"${data.elementId}\"\n            role=\"option\"\n            >\n            ${data.label}\n          </div>\n        `);\n        const actualOutput = templates.choice(choiceOptions, data, itemSelectText);\n\n        expectEqualElements(actualOutput, expectedOutput);\n      });\n    });\n\n    describe('disabled state', () => {\n      beforeEach(() => {\n        data = {\n          ...data,\n          disabled: true,\n        };\n      });\n\n      it('returns expected html', () => {\n        const expectedOutput = strToEl(`\n          <div\n            class=\"${getClassNames(choiceOptions.classNames.item).join(' ')} ${getClassNames(\n              choiceOptions.classNames.itemChoice,\n            ).join(' ')} ${getClassNames(choiceOptions.classNames.itemDisabled).join(' ')}\"\n            data-select-text=\"${itemSelectText}\"\n            data-choice\n            data-id=\"${data.id}\"\n            data-value=\"${data.value}\"\n            data-choice-disabled\n            aria-disabled=\"true\"\n            id=\"${data.elementId}\"\n            role=\"option\"\n            >\n            ${data.label}\n          </div>\n        `);\n        const actualOutput = templates.choice(choiceOptions, data, itemSelectText);\n\n        expectEqualElements(actualOutput, expectedOutput);\n      });\n    });\n\n    describe('selected state', () => {\n      beforeEach(() => {\n        data = {\n          ...data,\n          selected: true,\n        };\n      });\n\n      it('returns expected html', () => {\n        const expectedOutput = strToEl(`\n          <div\n            class=\"${getClassNames(choiceOptions.classNames.item).join(' ')} ${getClassNames(\n              choiceOptions.classNames.itemChoice,\n            ).join(\n              ' ',\n            )} ${choiceOptions.classNames.selectedState} ${getClassNames(choiceOptions.classNames.itemSelectable).join(' ')}\"\n            data-select-text=\"${itemSelectText}\"\n            data-choice\n            data-id=\"${data.id}\"\n            data-value=\"${data.value}\"\n            data-choice-selectable\n            aria-selected=\"true\"\n            id=\"${data.elementId}\"\n            role=\"option\"\n            >\n            ${data.label}\n          </div>\n        `);\n        const actualOutput = templates.choice(choiceOptions, data, itemSelectText);\n\n        expectEqualElements(actualOutput, expectedOutput);\n      });\n    });\n\n    describe('placeholder', () => {\n      beforeEach(() => {\n        data = {\n          ...data,\n          placeholder: true,\n        };\n      });\n\n      it('returns expected html', () => {\n        const expectedOutput = strToEl(`\n          <div\n            class=\"${getClassNames(choiceOptions.classNames.item).join(' ')} ${getClassNames(\n              choiceOptions.classNames.itemChoice,\n            ).join(\n              ' ',\n            )} ${choiceOptions.classNames.placeholder} ${getClassNames(choiceOptions.classNames.itemSelectable).join(' ')}\"\n            data-select-text=\"${itemSelectText}\"\n            data-choice\n            data-id=\"${data.id}\"\n            data-value=\"${data.value}\"\n            data-choice-selectable\n            aria-selected=\"false\"\n            id=\"${data.elementId}\"\n            role=\"option\"\n            >\n            ${data.label}\n          </div>\n        `);\n        const actualOutput = templates.choice(choiceOptions, data, itemSelectText);\n\n        expectEqualElements(actualOutput, expectedOutput);\n      });\n    });\n\n    describe('child of group', () => {\n      beforeEach(() => {\n        data = {\n          ...data,\n          group: { id: 1, label: 'test' },\n        };\n      });\n\n      it('returns expected html', () => {\n        const expectedOutput = strToEl(`\n          <div\n            class=\"${getClassNames(choiceOptions.classNames.item).join(' ')} ${getClassNames(\n              choiceOptions.classNames.itemChoice,\n            ).join(' ')} ${getClassNames(choiceOptions.classNames.itemSelectable).join(' ')}\"\n            data-select-text=\"${itemSelectText}\"\n            data-choice\n            data-id=\"${data.id}\"\n            data-value=\"${data.value}\"\n            data-group-id=\"${data.groupId}\"\n            data-choice-selectable\n            aria-selected=\"false\"\n            id=\"${data.elementId}\"\n            role=\"treeitem\"\n            >\n            ${data.label}\n          </div>\n        `);\n        const actualOutput = templates.choice(choiceOptions, data, itemSelectText, 'Group text');\n\n        expectEqualElements(actualOutput, expectedOutput);\n      });\n    });\n  });\n\n  describe('input', () => {\n    const templates = shimTemplates('input');\n    const inputOptions = createOptionsWithPartialClasses({\n      input: 'class-1',\n      inputCloned: 'class-2',\n    });\n\n    it('returns expected html', () => {\n      /*\n        Following attributes are not supported by JSDOM, so, can't compare\n          autocapitalize=\"off\"\n          spellcheck=\"false\"\n      */\n      const expectedOutput = strToEl(`\n        <input\n          type=\"search\"\n          class=\"${getClassNames(inputOptions.classNames.input).join(' ')} ${getClassNames(inputOptions.classNames.inputCloned).join(' ')}\"\n          autocomplete=\"off\"\n          aria-autocomplete=\"list\"\n          aria-label=\"test placeholder\"\n        >\n      `);\n      const actualOutput = templates.input(inputOptions, 'test placeholder');\n\n      expectEqualElements(actualOutput, expectedOutput);\n    });\n  });\n\n  describe('dropdown', () => {\n    const templates = shimTemplates('select');\n    const dropdownOptions = createOptionsWithPartialClasses({\n      list: 'class-1',\n      listDropdown: 'class-2',\n    });\n\n    it('returns expected html', () => {\n      const expectedOutput = strToEl(\n        `<div class=\"${getClassNames(dropdownOptions.classNames.list).join(' ')} ${getClassNames(dropdownOptions.classNames.listDropdown).join(' ')}\" aria-expanded=\"false\"></div>`,\n      );\n      const actualOutput = templates.dropdown(dropdownOptions);\n\n      expectEqualElements(actualOutput, expectedOutput);\n    });\n  });\n\n  describe('notice', () => {\n    const templates = shimTemplates('select');\n    const noticeOptions = createOptionsWithPartialClasses({\n      item: 'class-1',\n      itemChoice: 'class-2',\n      noResults: 'class-3',\n      noChoices: 'class-4',\n    });\n\n    const label = 'test';\n\n    it('returns expected html', () => {\n      const expectedOutput = strToEl(`\n        <div class=\"${getClassNames(noticeOptions.classNames.item).join(' ')} ${getClassNames(noticeOptions.classNames.itemChoice).join(' ')}\">\n          ${label}\n        </div>\n      `);\n      const actualOutput = templates.notice(noticeOptions, label, '');\n\n      expectEqualElements(actualOutput, expectedOutput);\n    });\n\n    describe('passing a notice type', () => {\n      describe('no results', () => {\n        it('adds no results classname', () => {\n          const { item, itemChoice, notice, noResults } = noticeOptions.classNames;\n          const expectedOutput = strToEl(`\n            <div class=\"${getClassNames(item).join(' ')} ${getClassNames(itemChoice).join(' ')} ${getClassNames(notice).join(' ')} ${getClassNames(noResults).join(' ')}\">\n              ${label}\n            </div>\n          `);\n          const actualOutput = templates.notice(noticeOptions, label, NoticeTypes.noResults);\n\n          expectEqualElements(actualOutput, expectedOutput);\n        });\n      });\n\n      describe('no choices', () => {\n        it('adds no choices classname', () => {\n          const { item, itemChoice, notice, noChoices } = noticeOptions.classNames;\n          const expectedOutput = strToEl(`\n            <div class=\"${getClassNames(item).join(' ')} ${getClassNames(itemChoice).join(' ')} ${getClassNames(notice).join(' ')} ${getClassNames(noChoices).join(' ')}\">\n              ${label}\n            </div>\n          `);\n          const actualOutput = templates.notice(noticeOptions, label, NoticeTypes.noChoices);\n\n          expectEqualElements(actualOutput, expectedOutput);\n        });\n      });\n    });\n  });\n\n  describe('option', () => {\n    const templates = shimTemplates('select');\n    let data;\n\n    beforeEach(() => {\n      data = {\n        disabled: false,\n        selected: false,\n        value: 'test value',\n        label: 'test label',\n      };\n    });\n\n    it('returns expected html', () => {\n      const expectedOutput = strToEl(\n        `<option value=\"${data.value}\" ${data.selected ? 'selected' : ''} ${data.disabled ? 'disabled' : ''}>${data.label}</option>`,\n      );\n      const actualOutput = templates.option(data);\n\n      expectEqualElements(actualOutput, expectedOutput);\n    });\n\n    describe('when selected', () => {\n      beforeEach(() => {\n        data = {\n          ...data,\n          selected: true,\n        };\n      });\n\n      it('sets selected attr to true', () => {\n        const output = templates.option(data);\n        expect(output.selected).to.equal(true);\n      });\n    });\n\n    describe('when disabled', () => {\n      beforeEach(() => {\n        data = {\n          ...data,\n          disabled: true,\n        };\n      });\n\n      it('sets disabled attr to true', () => {\n        const output = templates.option(data);\n        expect(output.disabled).to.equal(true);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test/setupFiles/window-matchMedia.ts",
    "content": "import { beforeAll } from 'vitest';\n\nbeforeAll(() => {\n  Object.defineProperty(globalThis.window, 'matchMedia', {\n    writable: true,\n    value: vi.fn().mockImplementation((query) => ({\n      matches: false,\n      media: query,\n      onchange: null,\n      addListener: vi.fn(), // deprecated\n      removeListener: vi.fn(), // deprecated\n      addEventListener: vi.fn(),\n      removeEventListener: vi.fn(),\n      dispatchEvent: vi.fn(),\n    })),\n  });\n});\n"
  },
  {
    "path": "test/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"es6\",\n    \"lib\": [\"es2017\", \"dom\"],\n    \"target\": \"ES2020\",\n    \"moduleResolution\": \"bundler\",\n    \"allowSyntheticDefaultImports\": true,\n    \"resolveJsonModule\": true,\n    \"esModuleInterop\": true,\n    \"strict\": false,\n    \"noImplicitAny\": false,\n    \"allowJs\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"strictNullChecks\": true,\n    \"newLine\": \"lf\",\n    \"declaration\": false,\n    \"declarationMap\": false,\n    \"types\": [\"@types/node\", \"vitest/globals\", \"vitest/jsdom\"],\n  },\n  \"include\": [\".\", \"../src\"],\n  \"exclude\": [\"**/node_modules\", \"**/public\"]\n}\n"
  },
  {
    "path": "test-e2e/bundle-test.ts",
    "content": "import { test as base } from '@playwright/test';\n\nexport type BundleTest = {\n  bundle: string | undefined;\n};\n\nexport const test = base.extend<BundleTest>({\n  // Define an option and provide a default value.\n  // We can later override it in the config.\n  bundle: [undefined, { option: true }],\n});\n"
  },
  {
    "path": "test-e2e/hars/0432285dab6a62ab5e6efaf4cb1272720e0c3f1b.json",
    "content": "{\"pagination\": {\"page\": 1, \"pages\": 20, \"per_page\": 50, \"items\": 980, \"urls\": {\"last\": \"https://api.discogs.com/artists/83080/releases?token=QBRmstCkwXEvCjTclCpumbtNwvVkEzGAdELXyRyW&page=20&per_page=50\", \"next\": \"https://api.discogs.com/artists/83080/releases?token=QBRmstCkwXEvCjTclCpumbtNwvVkEzGAdELXyRyW&page=2&per_page=50\"}}, \"releases\": [{\"id\": 11923761, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"Cass, Comp, Promo, C90\", \"label\": \"Rough Trade\", \"title\": \"The Smiths Session Compilation\", \"resource_url\": \"https://api.discogs.com/releases/11923761\", \"role\": \"Main\", \"artist\": \"The Smiths\", \"year\": 1983, \"thumb\": \"https://i.discogs.com/cNZigfLoB39e7KQMzxN2YlhTsJ_C8OOqc-V5sCznsQE/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTExOTIz/NzYxLTE1MjQ4MzY0/NTctNjc4My5wbmc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 169, \"in_collection\": 2}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 15040493, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"Cass, Advance, Comp\", \"label\": \"Rough Trade\", \"title\": \"The Smiths Session II\", \"resource_url\": \"https://api.discogs.com/releases/15040493\", \"role\": \"Main\", \"artist\": \"The Smiths\", \"year\": 1983, \"thumb\": \"https://i.discogs.com/RR2ixVfKATXYXKN1mpk5ao0v_RtruumV5rFfOAeO9QU/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTE1MDQw/NDkzLTE1ODU4Nzk3/MTItNjczNS5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 94, \"in_collection\": 3}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 2883079, \"title\": \"Reel Around The Fountain / Jeane\", \"type\": \"master\", \"main_release\": 673680, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/2883079\", \"year\": 1983, \"thumb\": \"https://i.discogs.com/l4koDCmZsjrK79iheZ0vM1DcbJxlgkgINB7I4748gr8/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTY3MzY4/MC0xNDUyMzk2Mzc5/LTczODYuanBlZw.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 561, \"in_collection\": 24}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 77418, \"title\": \"Hand In Glove\", \"type\": \"master\", \"main_release\": 452932, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/77418\", \"year\": 1983, \"thumb\": \"https://i.discogs.com/Q-WwZqJ7P75wys53aAM5aLJnMXMZDKOO3y7rYN7W0y0/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTQ1Mjkz/Mi0xMTY5OTA2Mzc1/LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 1144, \"in_collection\": 1727}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 6882, \"title\": \"This Charming Man\", \"type\": \"master\", \"main_release\": 452928, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/6882\", \"year\": 1983, \"thumb\": \"https://i.discogs.com/6cqMYiwVcK89vPpfi9tMP8iUC0DiuI06RAMVdQKcNr4/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTQ1Mjky/OC0xMTY5NzQyNzAy/LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 974, \"in_collection\": 2339}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 672262, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"12\\\", Promo, Smplr\", \"label\": \"Sire, Rough Trade\", \"title\": \"Selections From The Smiths\", \"resource_url\": \"https://api.discogs.com/releases/672262\", \"role\": \"Main\", \"artist\": \"The Smiths\", \"year\": 1984, \"thumb\": \"https://i.discogs.com/H2b2xplsmMQWBnJzL7B8evhAP-1QFaGrIbiDcaQFDkc/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTY3MjI2/Mi0xMjkyMTA5ODU3/LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 283, \"in_collection\": 279}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 31423556, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"7\\\", TP\", \"label\": \"Rough Trade\", \"title\": \"Still Ill\", \"resource_url\": \"https://api.discogs.com/releases/31423556\", \"role\": \"Main\", \"artist\": \"The Smiths\", \"year\": 1984, \"thumb\": \"https://i.discogs.com/j5h_PGVgzQT5yXXTrZ6t2gN1APG_X6cC5J29c6tQwRA/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTMxNDIz/NTU2LTE3MjMwNDAw/NDctNDQ5NC5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 7, \"in_collection\": 0}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 4157, \"title\": \"Heaven Knows I'm Miserable Now\", \"type\": \"master\", \"main_release\": 410864, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/4157\", \"year\": 1984, \"thumb\": \"https://i.discogs.com/pk_Z1-xCRT8rEzOpejb9iKMLDy-nMbOMxRQ2SOe66aE/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTQxMDg2/NC0xNTIxMzg2MjAy/LTMwMzUuanBlZw.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 790, \"in_collection\": 3011}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 4174, \"title\": \"How Soon Is Now?\", \"type\": \"master\", \"main_release\": 586504, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/4174\", \"year\": 1984, \"thumb\": \"https://i.discogs.com/2dnKS0WW0-FnazPT6nHmW9H8mBFVjyrNTfUt2gTTWYA/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTU4NjUw/NC0xNjQ0MzQxNjQ0/LTQzMTUuanBlZw.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 890, \"in_collection\": 1689}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 20048, \"title\": \"Hatful Of Hollow\", \"type\": \"master\", \"main_release\": 382135, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/20048\", \"year\": 1984, \"thumb\": \"https://i.discogs.com/loiGnaRNkhy9V791RiYThTLYEGlblxcYmb-39VLyQWQ/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTM4MjEz/NS0xNjY4MTM5NDE5/LTk5NjguanBlZw.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 5149, \"in_collection\": 15062}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 20086, \"title\": \"What Difference Does It Make?\", \"type\": \"master\", \"main_release\": 495324, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/20086\", \"year\": 1984, \"thumb\": \"https://i.discogs.com/BY9G-UPPCQFAaiAyV6VaRQ926ScFuHlPZypbu4wP-HU/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTQ5NTMy/NC0xMzM5ODU4ODQz/LTUxNDkuanBlZw.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 527, \"in_collection\": 2357}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 20093, \"title\": \"William, It Was Really Nothing\", \"type\": \"master\", \"main_release\": 374697, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/20093\", \"year\": 1984, \"thumb\": \"https://i.discogs.com/qSxgsAcc1MwqFmh8k6VPHRbCOi2K3v3cmN7jbV7XtDk/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTM3NDY5/Ny0xMjM5NDg5MjY4/LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 1078, \"in_collection\": 3397}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 21130, \"title\": \"Still Ill\", \"type\": \"master\", \"main_release\": 385522, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/21130\", \"year\": 1984, \"thumb\": \"https://i.discogs.com/4I3lvhPEhfESzYcFzpMpnWbKOa58aSyDOZTAQbG1tWE/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTM4NTUy/Mi0xMjMwODUwNTQ3/LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 767, \"in_collection\": 941}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 4264, \"title\": \"The Smiths\", \"type\": \"master\", \"main_release\": 370207, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/4264\", \"year\": 1984, \"thumb\": \"https://i.discogs.com/COOEvpRyjpUnt2P4lc2OKg8WbH2Kr2X6kc0u6wrFr9o/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTM3MDIw/Ny0xNzIwMTk1NTQx/LTk0NjcuanBlZw.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 3916, \"in_collection\": 7726}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 1310946, \"title\": \"Still Ill / You've Got Everything Now\", \"type\": \"master\", \"main_release\": 673683, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/1310946\", \"year\": 1984, \"thumb\": \"https://i.discogs.com/1-4pLjtmaxKfExhjrSTb2s9s4tPGkkvo7KYDCms2ldk/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTY3MzY4/My0xMjMwODUwNjE5/LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 323, \"in_collection\": 262}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 7535515, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"Acetate, 10\\\"\", \"label\": \"Rough Trade\", \"title\": \"Meat Is Murder / Barbarism Begins At Home\", \"resource_url\": \"https://api.discogs.com/releases/7535515\", \"role\": \"Main\", \"artist\": \"The Smiths\", \"year\": 1985, \"thumb\": \"https://i.discogs.com/NzLrfv-CFz0xZf9efpMuI3c1A7bnbnuEMGdrQFVndII/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTc1MzU1/MTUtMTQ0MzQ3ODk2/OS00NTEwLmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 163, \"in_collection\": 3}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 9743586, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"LP, Promo, Transcription\", \"label\": \"Sire, Rough Trade\", \"title\": \"The Warner Bros. Music Show\", \"resource_url\": \"https://api.discogs.com/releases/9743586\", \"role\": \"Main\", \"artist\": \"The Smiths / The Blasters\", \"year\": 1985, \"thumb\": \"https://i.discogs.com/BHBX5D6i7ycx8PuillpHFIpmW5DblLqKH4QMwa_qO3U/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTk3NDM1/ODYtMTQ4NTY4MzU3/Ny05OTMxLmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 131, \"in_collection\": 85}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 19878169, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"Cass, Album + Cass, Album + Cass, Album + Comp, Lt\", \"label\": \"Transmedia\", \"title\": \"The Smiths / Meat Is Murder / Hatful Of Hollow\", \"resource_url\": \"https://api.discogs.com/releases/19878169\", \"role\": \"Main\", \"artist\": \"The Smiths\", \"year\": 1985, \"thumb\": \"https://i.discogs.com/pPh9HvODVQteMeSHR38463chEL_5iiEoOQfAPZ33lIw/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTE5ODc4/MTY5LTE2MjkxMDkx/ODMtNjQ1MS5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 53, \"in_collection\": 1}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 21019, \"title\": \"Barbarism Begins At Home / Shakespeare's Sister\", \"type\": \"master\", \"main_release\": 685199, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/21019\", \"year\": 1985, \"thumb\": \"https://i.discogs.com/XeqI5kAPXtVSW9NyFCN0KQDt0H_lMTuksE1W7MLrV4Y/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTY4NTE5/OS0xMjMwODUzMjEw/LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 750, \"in_collection\": 1017}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 790096, \"title\": \"In Concert-354\", \"type\": \"master\", \"main_release\": 8071030, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/790096\", \"year\": 1985, \"thumb\": \"https://i.discogs.com/FUWW5zkuZLcVahENShfRSpCjKE-SLGrWU3TZrhaMCfg/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTgwNzEw/MzAtMTUwNTgzOTYx/OC0xNzAxLmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 603, \"in_collection\": 16}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 4186, \"title\": \"Meat Is Murder\", \"type\": \"master\", \"main_release\": 373240, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/4186\", \"year\": 1985, \"thumb\": \"https://i.discogs.com/pK2B7p1NbuVniv31CSvktBeT1iHszldtp6jU690--98/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTM3MzI0/MC0xMTg5NzEyNjQ0/LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 4335, \"in_collection\": 9264}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 20111, \"title\": \"Shakespeare's Sister\", \"type\": \"master\", \"main_release\": 531424, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/20111\", \"year\": 1985, \"thumb\": \"https://i.discogs.com/0XjqHraWnubEuAkntz8cnaLsIpmuPx4HbuVtogUcYmM/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTUzMTQy/NC0xMjMwODUyNjk2/LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 526, \"in_collection\": 2761}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 20118, \"title\": \"That Joke Isn't Funny Anymore\", \"type\": \"master\", \"main_release\": 490713, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/20118\", \"year\": 1985, \"thumb\": \"https://i.discogs.com/qBE75OeGBf0Chn29tYu7bbid9adEVAzR4AXiZy8oEIg/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTQ5MDcx/My0xNDk3Nzk2NjM3/LTk0MTMuanBlZw.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 634, \"in_collection\": 3063}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 21146, \"title\": \"The Boy With The Thorn In His Side\", \"type\": \"master\", \"main_release\": 382177, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/21146\", \"year\": 1985, \"thumb\": \"https://i.discogs.com/ByNXmbew3aA33kOqVuSFxrvWbZhVMr-92gXgvYWRhhU/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTM4MjE3/Ny0xMjMwODUzNjE2/LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 783, \"in_collection\": 2721}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 21160, \"title\": \"The Headmaster Ritual\", \"type\": \"master\", \"main_release\": 546534, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/21160\", \"year\": 1985, \"thumb\": \"https://i.discogs.com/ER2Fq3db1VvNIHE8Vz7uQ2X66xQdOukGjGTOWcEpjIs/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTU0NjUz/NC0xMjMwODUzNDI5/LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 578, \"in_collection\": 1221}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 1014957, \"title\": \"Meat Is Murder\", \"type\": \"master\", \"main_release\": 7535593, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/1014957\", \"year\": 1985, \"thumb\": \"https://i.discogs.com/_2ImJIrDqfGSJzZDNo4huekodTZM9SNuEwEe7cQ3yn4/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTc1MzU1/OTMtMTQ0MzQ4MDYy/MS02ODIyLmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 208, \"in_collection\": 9}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 620441, \"title\": \"How Soon Is Now? / Shakespeare's Sister\", \"type\": \"master\", \"main_release\": 1625522, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/620441\", \"year\": 1985, \"thumb\": \"https://i.discogs.com/AtjvsZxKyDOgiuUJB_pSmxUuK694u_YBnVGKNm2vCI0/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTE2MjU1/MjItMTIzMjk4NDc5/Ny5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 339, \"in_collection\": 322}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 10264260, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"CD, Album + CD, Album, RE + Comp\", \"label\": \"Rough Trade\", \"title\": \"Meat Is Murder / The Smiths\", \"resource_url\": \"https://api.discogs.com/releases/10264260\", \"role\": \"Main\", \"artist\": \"The Smiths\", \"year\": 1986, \"thumb\": \"https://i.discogs.com/DzNxWvv4QRBTFGRrdz0xQe-Yrw6qKvZocHg95a3_iMs/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTEwMjY0/MjYwLTE1ODAyODAw/NjQtMzUzOS5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 72, \"in_collection\": 18}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 512624, \"title\": \"The Queen Is Dead / Hatful Of Hollow\", \"type\": \"master\", \"main_release\": 479903, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/512624\", \"year\": 1986, \"thumb\": \"https://i.discogs.com/Ux-te_9pbgmu2e16E6yKgsbz5qMKLqcEHvNcZuEgVOQ/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTQ3OTkw/My0xNTgwMjc5NTY3/LTEwOTEuanBlZw.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 105, \"in_collection\": 13}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 21129, \"title\": \"Some Girls Are Bigger Than Others\", \"type\": \"master\", \"main_release\": 2071744, \"artist\": \"Smiths*\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/21129\", \"year\": 1986, \"thumb\": \"https://i.discogs.com/ekLrsdqWXQZysP8qj2yxTu0PS9E3oIdEpVvW54ge6ds/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTIwNzE3/NDQtMTI2MjM3NDEw/Ni5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 493, \"in_collection\": 157}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 4235, \"title\": \"Panic\", \"type\": \"master\", \"main_release\": 495333, \"artist\": \"Smiths*\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/4235\", \"year\": 1986, \"thumb\": \"https://i.discogs.com/ImFMnaTqSpWvNI_dcGIsus3HQeRh9K7kI3RvSv0Kq28/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTQ5NTMz/My0xMTIzMzYwODcw/LmpwZw.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 539, \"in_collection\": 1699}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 20137, \"title\": \"The Queen Is Dead\", \"type\": \"master\", \"main_release\": 494927, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/20137\", \"year\": 1986, \"thumb\": \"https://i.discogs.com/h-22qMW4NhaGU_UkQdgiGAhpIGcEnr1u2rWeV6Bip2Y/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTQ5NDky/Ny0xMjMwODU0MDIz/LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 9202, \"in_collection\": 11734}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 2732795, \"title\": \"There Is A Light That Never Goes Out\", \"type\": \"master\", \"main_release\": 3909976, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/2732795\", \"year\": 1986, \"thumb\": \"https://i.discogs.com/s02mptwC9eqP4Nyuljf3GfDFbYPZa61RvQ4tk8vKUjE/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTM5MDk5/NzYtMTM2Nzk2Mzkx/OS03MjU2LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 635, \"in_collection\": 74}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 2897197, \"title\": \"You Just Haven't Earned It Yet Baby \", \"type\": \"master\", \"main_release\": 7444232, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/2897197\", \"year\": 1986, \"thumb\": \"https://i.discogs.com/pQtu2gQfz6zZTKNOIqcU79mPzACIcuRvMD65l22fev4/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTc0NDQy/MzItMTY3MDUzNjAy/Ni01MDk1LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 216, \"in_collection\": 8}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 4005, \"title\": \"Ask\", \"type\": \"master\", \"main_release\": 525785, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/4005\", \"year\": 1986, \"thumb\": \"https://i.discogs.com/zKWLKO5wETuCefMgL_4zyje87NGfen2U28V1kMg4MA8/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTUyNTc4/NS0xNjA1MTE3MTU0/LTk1MzkuanBlZw.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 379, \"in_collection\": 2056}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 4032, \"title\": \"Bigmouth Strikes Again\", \"type\": \"master\", \"main_release\": 490734, \"artist\": \"Smiths*\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/4032\", \"year\": 1986, \"thumb\": \"https://i.discogs.com/vOYDy0cPqYgyVUo1Zw83YltsaasR1OfCu4IhN50TIcE/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTQ5MDcz/NC0xMTIyNDAxMjQ1/LmpwZw.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 858, \"in_collection\": 2738}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 1673558, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"7\\\", Jukebox\", \"label\": \"Rough Trade, CGD\", \"title\": \"Girlfriend In A Coma / True Faith\", \"resource_url\": \"https://api.discogs.com/releases/1673558\", \"role\": \"Main\", \"artist\": \"The Smiths / New Order\", \"year\": 1987, \"thumb\": \"https://i.discogs.com/TPM4BaA2ij06Q-Q88T0lGRr5wOc_-ZfvCm4MIH3J41k/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTE2NzM1/NTgtMTM4NDM3OTk5/NS0zNTMwLmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 379, \"in_collection\": 127}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 3995481, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"7\\\", Jukebox, Promo\", \"label\": \"Rough Trade, CGD\", \"title\": \"Ask / Il Garibaldi Innamorato\", \"resource_url\": \"https://api.discogs.com/releases/3995481\", \"role\": \"Main\", \"artist\": \"The Smiths / Sergio Caputo\", \"year\": 1987, \"thumb\": \"https://i.discogs.com/9jWAy7tEzoFoas1f4ufCRNwcbwFTU0wqsAMXvnqyrJ0/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTM5OTU0/ODEtMTU5MzI0MjEx/MC0yNzI5LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 123, \"in_collection\": 94}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 27102675, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"Box, Comp, Ltd, Num, Pac + 4x7\\\", M/Print\", \"label\": \"Line Records, Line Records, Line Records, Line Records\", \"title\": \"Stop Me If You Think You've Heard This One Before / Girlfriend In A Coma / Sheila Take A Bow / Is It Really So Strange\", \"resource_url\": \"https://api.discogs.com/releases/27102675\", \"role\": \"Main\", \"artist\": \"The Smiths\", \"year\": 1987, \"thumb\": \"https://i.discogs.com/D5777lCHLAG3UFo8VLTGkIVsNzXUZ7Vx9NXq4tXYTzI/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTI3MTAy/Njc1LTE2ODQzMDE2/MjMtODAxNC5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 46, \"in_collection\": 6}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 21034, \"title\": \"Last Night I Dreamt That Somebody Loved Me\", \"type\": \"master\", \"main_release\": 490744, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/21034\", \"year\": 1987, \"thumb\": \"https://i.discogs.com/pbWTCFwTqGbWudPYbOvS-ZStilay9x_CTCpKtgvqrm0/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTQ5MDc0/NC0xNTIwNjkwODg5/LTM0MDYuanBlZw.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 642, \"in_collection\": 1673}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 21051, \"title\": \"Rank\", \"type\": \"master\", \"main_release\": 451760, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/21051\", \"year\": 1987, \"thumb\": \"https://i.discogs.com/-OVsrjK3jWTnI_N42PKhQv_pmNMpQK0L9ThrKaRSWDI/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTQ1MTc2/MC0xMjMwOTAzNzI5/LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 1456, \"in_collection\": 4368}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 21109, \"title\": \"I Started Something I Couldn't Finish\", \"type\": \"master\", \"main_release\": 464985, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/21109\", \"year\": 1987, \"thumb\": \"https://i.discogs.com/mNaoiBYIwM1AVt9MqgaYVqzxLcPm5Bf-m8s8RM_9RxE/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTQ2NDk4/NS0xNTIwNzA1NDU0/LTM5ODYuanBlZw.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 592, \"in_collection\": 2247}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 21113, \"title\": \"Shoplifters Of The World Unite\", \"type\": \"master\", \"main_release\": 385496, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/21113\", \"year\": 1987, \"thumb\": \"https://i.discogs.com/JgOKmRkPzT8AhxP_ZzvhQU2OxeYF0rpZRMK7RVTKh78/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTM4NTQ5/Ni0xMjM4ODg4NjIw/LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 639, \"in_collection\": 3121}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 21116, \"title\": \"Sheila Take A Bow\", \"type\": \"master\", \"main_release\": 385511, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/21116\", \"year\": 1987, \"thumb\": \"https://i.discogs.com/QRjtzXqCzKwuuDhNZnDUfDw6LYL_HNlaV0iCz8OuRe4/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTM4NTUx/MS0xMjgxODk2ODgw/LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 635, \"in_collection\": 2738}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 21136, \"title\": \"Stop Me If You Think You've Heard This One Before\", \"type\": \"master\", \"main_release\": 1579000, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/21136\", \"year\": 1987, \"thumb\": \"https://i.discogs.com/wmN4tfmSEK2rVBxWowKHCnZaDLAex_RJ8Dlg99xV6uE/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTE1Nzkw/MDAtMTI3NTM3MTI1/OC5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 459, \"in_collection\": 357}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 21143, \"title\": \"Strangeways, Here We Come\", \"type\": \"master\", \"main_release\": 373250, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/21143\", \"year\": 1987, \"thumb\": \"https://i.discogs.com/K6S3v8gHtaMZPzM8D5SsZbZlLt2GfGRRRejmZAzFxh0/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTM3MzI1/MC0xNjQ1ODM0MDEw/LTg1NTQuanBlZw.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 3298, \"in_collection\": 8023}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 21169, \"title\": \"The World Won't Listen\", \"type\": \"master\", \"main_release\": 418263, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/21169\", \"year\": 1987, \"thumb\": \"https://i.discogs.com/svGEMGBRTs4NJLByd8vXocpp0L69bjsxBB6zPL76c10/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTQxODI2/My0xNDk2MzA3NDM0/LTQzODEuanBlZw.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 1086, \"in_collection\": 6262}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 4054, \"title\": \"Girlfriend In A Coma\", \"type\": \"master\", \"main_release\": 388479, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/4054\", \"year\": 1987, \"thumb\": \"https://i.discogs.com/_G_b4Q_1vsFgXVTZwyVqR8rhmpdBHYFDtP8KaeyewGw/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTM4ODQ3/OS0xMjMwOTAyNjc3/LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 682, \"in_collection\": 2979}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 20975, \"title\": \"Louder Than Bombs\", \"type\": \"master\", \"main_release\": 598368, \"artist\": \"The Smiths\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/20975\", \"year\": 1987, \"thumb\": \"https://i.discogs.com/Z11fpKkE00FZeDf9bCmE6HfZ1RNA_TVZzw-HJ-EV3hM/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTU5ODM2/OC0xMjQxMzU0OTUx/LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 419, \"in_collection\": 825}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 596552, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"Flexi, 7\\\", Shape, S/Sided\", \"label\": \"The Catalogue\", \"title\": \"London\", \"resource_url\": \"https://api.discogs.com/releases/596552\", \"role\": \"Main\", \"artist\": \"The Smiths\", \"year\": 1988, \"thumb\": \"https://i.discogs.com/NZz5CWmlUVdFN_8ijCsFInSmqzn_YAiaUr68OCdY1kk/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTU5NjU1/Mi0xNTIxNDY2Nzgx/LTc1NjIuanBlZw.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 184, \"in_collection\": 583}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}]}"
  },
  {
    "path": "test-e2e/hars/69c6136c671f1173ee6d6596d125e821dea44a4f.json",
    "content": "{\"pagination\": {\"page\": 1, \"pages\": 8, \"per_page\": 50, \"items\": 362, \"urls\": {\"last\": \"https://api.discogs.com/artists/55980/releases?token=QBRmstCkwXEvCjTclCpumbtNwvVkEzGAdELXyRyW&page=8&per_page=50\", \"next\": \"https://api.discogs.com/artists/55980/releases?token=QBRmstCkwXEvCjTclCpumbtNwvVkEzGAdELXyRyW&page=2&per_page=50\"}}, \"releases\": [{\"id\": 4396593, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"CDr\", \"label\": \"Not On Label (The Strokes Self-released)\", \"title\": \"The Strokes\", \"resource_url\": \"https://api.discogs.com/releases/4396593\", \"role\": \"Main\", \"artist\": \"The Strokes\", \"year\": 2000, \"thumb\": \"https://i.discogs.com/PGWu1WUkAKPPom4DWq7HCg7DU_pGYGZjGkycvdnEtHI/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTQzOTY1/OTMtMTM2NDAyOTI4/NC0xNTAwLnBuZw.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 290, \"in_collection\": 10}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 4415980, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"CDr\", \"label\": \"Not On Label (The Strokes Self-released)\", \"title\": \"The Strokes\", \"resource_url\": \"https://api.discogs.com/releases/4415980\", \"role\": \"Main\", \"artist\": \"The Strokes\", \"year\": 2000, \"thumb\": \"https://i.discogs.com/QOyryNMjyLhj0gND1kEU-ciD9z_mkYbstnQkgUqpoHc/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTQ0MTU5/ODAtMTM2NDkzOTM5/Ny0yNDAwLnBuZw.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 141, \"in_collection\": 4}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 667587, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"CD, Promo\", \"label\": \"RCA, BMG\", \"title\": \"The Strokes\", \"resource_url\": \"https://api.discogs.com/releases/667587\", \"role\": \"Main\", \"artist\": \"The Strokes\", \"year\": 2001, \"thumb\": \"https://i.discogs.com/GAOYTjEkmQMB4erlI22c9eSt-D6tlGjyaMeSd7tiGr4/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTY2NzU4/Ny0xNjcyODE5OTEx/LTM2NzcuanBlZw.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 52, \"in_collection\": 86}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 4403337, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"CDr, Comp, TP\", \"label\": \"Rough Trade\", \"title\": \"Singles Compilation\", \"resource_url\": \"https://api.discogs.com/releases/4403337\", \"role\": \"Main\", \"artist\": \"The Stokes*\", \"year\": 2001, \"thumb\": \"https://i.discogs.com/LCwsXLm7NaM9AgxLNqKjsAdqR09x8Nl4oYpN-Qo_Wns/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTQ0MDMz/MzctMTM2NDkyNDkx/NS0yOTczLmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 34, \"in_collection\": 2}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 4407807, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"CD, Single, Promo\", \"label\": \"BMG, RCA\", \"title\": \"Last Nite / That Day\", \"resource_url\": \"https://api.discogs.com/releases/4407807\", \"role\": \"Main\", \"artist\": \"The Strokes / Natalie Imbruglia\", \"year\": 2001, \"thumb\": \"https://i.discogs.com/mk1rW_9SqXHyrC3vm1aT0eJagQBkFbsgDaH4Uv3AP1c/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTQ0MDc4/MDctMTYzMDk2MzI0/MC0yODM3LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 29, \"in_collection\": 3}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 4425937, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"CD, Promo, Smplr\", \"label\": \"BMG Denmark, RCA\", \"title\": \"Is This It (Snippets From The Album)\", \"resource_url\": \"https://api.discogs.com/releases/4425937\", \"role\": \"Main\", \"artist\": \"The Strokes\", \"year\": 2001, \"thumb\": \"https://i.discogs.com/7vL2HVZuzyFGYPghYPrKi9xA36WFhQ8NIkA1sliZKFQ/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTQ0MjU5/MzctMTM2NjAxNTQ1/Ni0yMDM3LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 30, \"in_collection\": 15}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 5333822, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"CD, Single, Promo\", \"label\": \"BMG Brasil, RCA\", \"title\": \"Soma\", \"resource_url\": \"https://api.discogs.com/releases/5333822\", \"role\": \"Main\", \"artist\": \"The Strokes\", \"year\": 2001, \"thumb\": \"https://i.discogs.com/Klbkl_dhMw3rXDj1Uzp_LSYoQKc8E2we476Tbma_vy4/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTUzMzM4/MjItMTM5MDc5MDE3/MC02NTQ0LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 42, \"in_collection\": 8}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 12347, \"title\": \"Is This It\", \"type\": \"master\", \"main_release\": 1310374, \"artist\": \"The Strokes\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/12347\", \"year\": 2001, \"thumb\": \"https://i.discogs.com/VSV15HRjwsqwYE-V3NgyROYAGqsF7w6JeNje3iTHnUg/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTEzMTAz/NzQtMTQ1Njk0MTMz/My0zMDY2LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 874, \"in_collection\": 450}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 12358, \"title\": \"The Modern Age\", \"type\": \"master\", \"main_release\": 1291065, \"artist\": \"The Strokes\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/12358\", \"year\": 2001, \"thumb\": \"https://i.discogs.com/gYOoi0PV5hwC-igkFBCW9TmcSwTzy0iRAYlfFXW-WTA/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTEyOTEw/NjUtMTU1OTIyNTQ4/Ny0zMzA5LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 103, \"in_collection\": 664}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 12369, \"title\": \"Hard To Explain\", \"type\": \"master\", \"main_release\": 1689058, \"artist\": \"The Strokes\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/12369\", \"year\": 2001, \"thumb\": \"https://i.discogs.com/05VEmyc6p7onXVwzX-JyEwugj9eQY_Jb2jpVxbQcz0I/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTE2ODkw/NTgtMTI1OTI3NDAw/My5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 558, \"in_collection\": 782}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 12378, \"title\": \"Last Nite\", \"type\": \"master\", \"main_release\": 918683, \"artist\": \"The Strokes\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/12378\", \"year\": 2001, \"thumb\": \"https://i.discogs.com/u_5XWVI7F9Rtk3ynlCoQ-9CVcyefRfn1tIK4FHICRwc/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTkxODY4/My0xMTc0MTI4NjYz/LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 716, \"in_collection\": 1108}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 2349016, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"DVD-V\", \"label\": \"BMG Music\", \"title\": \"The Videos And More\", \"resource_url\": \"https://api.discogs.com/releases/2349016\", \"role\": \"Main\", \"artist\": \"The Strokes\", \"year\": 2002, \"thumb\": \"https://i.discogs.com/g4ubWUwvVcsebc486Gld-Mqui_uwQv2trx5nh8Dd3do/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTIzNDkw/MTYtMTM0OTU4NjA3/My0zMjY2LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 49, \"in_collection\": 57}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 4407738, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"DVD, D/Sided, Promo, DVD\", \"label\": \"RCA\", \"title\": \"Live In Iceland 04/02/2002\", \"resource_url\": \"https://api.discogs.com/releases/4407738\", \"role\": \"Main\", \"artist\": \"The Strokes\", \"year\": 2002, \"thumb\": \"https://i.discogs.com/vU1EYHGEdQ0vb_wqwCePNP3KHTqaAZKYxmBxTJjbxmw/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTQ0MDc3/MzgtMTM2NDkyNDc4/NS00MDEyLmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 108, \"in_collection\": 50}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 15234570, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"DVD-V, Promo\", \"label\": \"BMG Music\", \"title\": \"The Strokes\", \"resource_url\": \"https://api.discogs.com/releases/15234570\", \"role\": \"Main\", \"artist\": \"The Strokes\", \"year\": 2002, \"thumb\": \"https://i.discogs.com/DXzLHho8Tq_9cbjWXOjJn4w2_-1zkSAFVNPg43V8DVs/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTE1MjM0/NTcwLTE1ODg0OTYz/MzEtNTk0Mi5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 16, \"in_collection\": 5}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 12385, \"title\": \"Someday\", \"type\": \"master\", \"main_release\": 1045089, \"artist\": \"The Strokes\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/12385\", \"year\": 2002, \"thumb\": \"https://i.discogs.com/nucqQcQmUoAD6r7RIW3amB2T_GKYxRTxo4PPz27Yjvo/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTEwNDUw/ODktMTYyODQ2MjI1/OC02Mzk4LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 695, \"in_collection\": 918}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 594487, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"CD, Promo\", \"label\": \"Rough Trade, The Observer\", \"title\": \"Exclusive 5 Track CD\", \"resource_url\": \"https://api.discogs.com/releases/594487\", \"role\": \"Main\", \"artist\": \"The Strokes\", \"year\": 2003, \"thumb\": \"https://i.discogs.com/TjkmVrWUoLBeiZ4N_Eg_0U2ZdeEgmSpuruIIOtT2hP4/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTU5NDQ4/Ny0xMjU3MjQ4MTI1/LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 80, \"in_collection\": 657}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 4403181, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"CD, Single, Ltd, Promo\", \"label\": \"BMG Italy, RCA\", \"title\": \"The Way It Is (Home Demo Version)\", \"resource_url\": \"https://api.discogs.com/releases/4403181\", \"role\": \"Main\", \"artist\": \"The Strokes\", \"year\": 2003, \"thumb\": \"https://i.discogs.com/yTZOPCneuoagNy4r3lES8qv_70f4GQNnL-MBdfGLIQE/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTQ0MDMx/ODEtMTM3MjU3Njcy/OC00MzczLmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 30, \"in_collection\": 17}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 4403231, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"CDr, Smplr\", \"label\": \"BMG Japan, RCA\", \"title\": \"Best Sampler\", \"resource_url\": \"https://api.discogs.com/releases/4403231\", \"role\": \"Main\", \"artist\": \"The Strokes\", \"year\": 2003, \"thumb\": \"https://i.discogs.com/S75K1-tB4gB3zvXgtEceWjU1Zz7mRpPlE49SJOQ6Zug/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTQ0MDMy/MzEtMTM2NDkyNDQw/My0zODA3LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 10, \"in_collection\": 2}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 6895935, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"CD\", \"label\": \"BMG Mexico, RCA\", \"title\": \"Reptilia / Harder To Breathe\", \"resource_url\": \"https://api.discogs.com/releases/6895935\", \"role\": \"Main\", \"artist\": \"The Strokes / Maroon 5\", \"year\": 2003, \"thumb\": \"https://i.discogs.com/oeH1Alg2F8-ijsiJabYVRYespjJuNI9KWObaHTbTlWM/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTY4OTU5/MzUtMTQyODk4Mzg0/Mi00NzMwLmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 24, \"in_collection\": 4}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 1711966, \"title\": \"Room On Fire\", \"type\": \"master\", \"main_release\": 13497501, \"artist\": \"The Strokes\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/1711966\", \"year\": 2003, \"thumb\": \"https://i.discogs.com/mpd5sJh1B2lRh2YY12GgHwV4oCqOQP-mNUvqTl6P7s0/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTEzNDk3/NTAxLTE1NTUzMjE5/MjItOTc2MS5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 19, \"in_collection\": 2}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 12395, \"title\": \"12:51\", \"type\": \"master\", \"main_release\": 377413, \"artist\": \"The Strokes\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/12395\", \"year\": 2003, \"thumb\": \"https://i.discogs.com/0TDphb2G26QIgZV6LRMBKAsA_o-YIo40cA1JbvcS8Wc/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTM3NzQx/My0xNTM4MzkwNjky/LTg1NDkuanBlZw.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 484, \"in_collection\": 1166}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 64237, \"title\": \"Reptilia / Modern Girls & Old Fashion Men\", \"type\": \"master\", \"main_release\": 2462131, \"artist\": \"The Strokes / Regina Spektor And The Strokes\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/64237\", \"year\": 2003, \"thumb\": \"https://i.discogs.com/dr7ZZwB6OsXPCOIC-GGiOBaR7q-iOujH87BY6J7Ab-w/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTI0NjIx/MzEtMTUzODQwNDE1/NS01NDk1LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 628, \"in_collection\": 503}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 12403, \"title\": \"Room On Fire\", \"type\": \"master\", \"main_release\": 1355727, \"artist\": \"The Strokes\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/12403\", \"year\": 2003, \"thumb\": \"https://i.discogs.com/w6X8A1LGAi1xYNREr8frvDFh3AgN_q2rshwMPl8kIdw/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTEzNTU3/MjctMTQ4NTI2OTEx/Ni04NzEzLmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 3767, \"in_collection\": 12049}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 215551, \"title\": \"The End Has No End\", \"type\": \"master\", \"main_release\": 377418, \"artist\": \"The Strokes\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/215551\", \"year\": 2003, \"thumb\": \"https://i.discogs.com/dGo9G4TxZBmmjVkVQ4BnrWvITTNyglqpPbw0WhW-ch0/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTM3NzQx/OC0xNTcxMDc5Njcz/LTE2NDcuanBlZw.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 481, \"in_collection\": 766}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 9970976, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"DVD-V\", \"label\": \"Strokes Picture\", \"title\": \"In Transit\", \"resource_url\": \"https://api.discogs.com/releases/9970976\", \"role\": \"Main\", \"artist\": \"The Strokes\", \"year\": 2004, \"thumb\": \"https://i.discogs.com/O9X-YUKDNWdiZMygiyXsaiZIyS8Dg09dAJ8boeRdkfM/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTk5NzA5/NzYtMTQ4OTQzNzcx/NS02NTg2LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 100, \"in_collection\": 33}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 16067475, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"CDr, Promo\", \"label\": \"Rough Trade\", \"title\": \"Live At Alexandra Place 5th December 2003\", \"resource_url\": \"https://api.discogs.com/releases/16067475\", \"role\": \"Main\", \"artist\": \"The Strokes\", \"year\": 2004, \"thumb\": \"https://i.discogs.com/5DDOKnziY1jjNQo2ppw5GcYZ7rp_qslaEbENLZsggnY/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTE2MDY3/NDc1LTE2MDI4NTU2/NzQtNzM5MS5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 102, \"in_collection\": 2}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 410896, \"title\": \"Elephant Song\", \"type\": \"master\", \"main_release\": 3393314, \"artist\": \"The Strokes\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/410896\", \"year\": 2004, \"thumb\": \"https://i.discogs.com/UMC68iyUay8VkPuf7YbPgFEmtijjFk5_8_p1h3Ls6HM/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTMzOTMz/MTQtMTMyODY1NTQ4/NS5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 102, \"in_collection\": 32}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 3074615, \"title\": \"Modern Girls & Old Fashion Men\", \"type\": \"master\", \"main_release\": 6658966, \"artist\": \"The Strokes & Regina Spektor\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/3074615\", \"year\": 2004, \"thumb\": \"https://i.discogs.com/CZSJw5z029bQvEW4D_C2gBHUeHy-90K0G-BNa2tfw4I/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTY2NTg5/NjYtMTQyNDAzNDgw/OC00NzYxLmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 25, \"in_collection\": 7}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 9969999, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"DVD-V, Fan\", \"label\": \"Sony BMG Music Entertainment (Australia) Pty Limited\", \"title\": \"Reptilia Live Big Day Out - 2004\", \"resource_url\": \"https://api.discogs.com/releases/9969999\", \"role\": \"Main\", \"artist\": \"The Strokes\", \"year\": 2005, \"thumb\": \"https://i.discogs.com/hol2KbYe0sbXQTGgMas9L5m_JWaob-uFaucv_g_lrqY/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTk5Njk5/OTktMTQ4OTQyNjQ5/NC0yMDYxLmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 15, \"in_collection\": 11}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 64208, \"title\": \"Juicebox\", \"type\": \"master\", \"main_release\": 579137, \"artist\": \"The Strokes\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/64208\", \"year\": 2005, \"thumb\": \"https://i.discogs.com/nPqAdXHaGvmrrFcG3a4rrPxivEWpoei_CRraiveeHN0/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTU3OTEz/Ny0xNTcwODA3NjAz/LTY1NDguanBlZw.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 338, \"in_collection\": 1397}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 64216, \"title\": \"You Only Live Once\", \"type\": \"master\", \"main_release\": 745201, \"artist\": \"The Strokes\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/64216\", \"year\": 2005, \"thumb\": \"https://i.discogs.com/wdhhnTdDaqR5LnUFFHxU7umvoz-GUAkI6eX6MMQKR28/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTc0NTIw/MS0xNTg0NjkzOTc1/LTc3OTcuanBlZw.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 708, \"in_collection\": 835}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 1755610, \"title\": \"First Impressions Of Earth (sampler)\", \"type\": \"master\", \"main_release\": 15281468, \"artist\": \"The Strokes\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/1755610\", \"year\": 2005, \"thumb\": \"https://i.discogs.com/TG5U92IPUIn57fXpFHilegjEpDe-srA5cz98yarj-i0/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTE1Mjgx/NDY4LTE1ODkxMjcy/MDgtMjE2Ni5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 14, \"in_collection\": 1}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 64228, \"title\": \"Heart In A Cage\", \"type\": \"master\", \"main_release\": 659606, \"artist\": \"The Strokes\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/64228\", \"year\": 2005, \"thumb\": \"https://i.discogs.com/UyMM6U-AfpYkXiPxk5V43MysqREq9IfonE9ybQ3DPeo/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTY1OTYw/Ni0xNTg0Njk0MjQ2/LTE5NjguanBlZw.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 710, \"in_collection\": 896}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 12410, \"title\": \"First Impressions Of Earth\", \"type\": \"master\", \"main_release\": 616517, \"artist\": \"The Strokes\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/12410\", \"year\": 2005, \"thumb\": \"https://i.discogs.com/rJcDNchQU5W-uRVaK4ONsPuJe7k4lg0EGK-a2iY6Lg8/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTYxNjUx/Ny0xNTk0NTc3MDMz/LTQyMjYuanBlZw.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 355, \"in_collection\": 1283}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 15057328, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"CDr, Promo\", \"label\": \"Rough Trade\", \"title\": \"Mercy Mercy Me (The Ecology)\", \"resource_url\": \"https://api.discogs.com/releases/15057328\", \"role\": \"Main\", \"artist\": \"The Strokes\", \"year\": 2006, \"thumb\": \"https://i.discogs.com/LDUROUzWbWdnQQAhFaI0KD37YsP_Yu1oUB1Lxcpqi18/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTE1MDU3/MzI4LTE1ODYxMDQ0/NDctOTg4Ny5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 18, \"in_collection\": 5}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 15057350, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"DVDr, DVD-V, Promo\", \"label\": \"Rough Trade\", \"title\": \"First Impressions Of Earth Videos\", \"resource_url\": \"https://api.discogs.com/releases/15057350\", \"role\": \"Main\", \"artist\": \"The Strokes\", \"year\": 2006, \"thumb\": \"https://i.discogs.com/NBiJg0_M7PjHfIXBaMH0hVnVENf06TTUWtxW805EN08/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTE1MDU3/MzUwLTE1ODYxMDQ2/MTQtNTEzNy5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 16, \"in_collection\": 3}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 6340237, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"CDr, Single, Promo\", \"label\": \"Rough Trade\", \"title\": \"Machu Picchu\", \"resource_url\": \"https://api.discogs.com/releases/6340237\", \"role\": \"Main\", \"artist\": \"The Strokes\", \"year\": 2011, \"thumb\": \"https://i.discogs.com/rX3Q6V_SA-0j7gjLUbsT9tBrVp1QdYRSU46OiiahdHs/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTYzNDAy/MzctMTQxNjg1MjQ3/NS0xMDU0LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 56, \"in_collection\": 13}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 320026, \"title\": \"Under Cover Of Darkness\", \"type\": \"master\", \"main_release\": 2791573, \"artist\": \"The Strokes\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/320026\", \"year\": 2011, \"thumb\": \"https://i.discogs.com/bJ_1OL-Oat8UyH2pM1ZR-Ba1R9kHA9fwLaBjfz3Ureg/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTI3OTE1/NzMtMTU4NDY5MzY3/Mi01OTk3LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 332, \"in_collection\": 993}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 319839, \"title\": \"Angles\", \"type\": \"master\", \"main_release\": 2785591, \"artist\": \"The Strokes\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/319839\", \"year\": 2011, \"thumb\": \"https://i.discogs.com/teG0IdSy0tJrypq8DgLUsTlL44GkPqveRBDGlZr2Ayk/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTI3ODU1/OTEtMTQxNjk0MTc3/NS00NzM4LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 414, \"in_collection\": 1289}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 1712367, \"title\": \"Taken For A Fool\", \"type\": \"master\", \"main_release\": 3056804, \"artist\": \"The Strokes\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/1712367\", \"year\": 2011, \"thumb\": \"https://i.discogs.com/a7p-0x-axUn2OLCI8bqln5GOO7f00Fv_d10rNjEU2fw/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTMwNTY4/MDQtMTMxNDIzMzU3/MC5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 397, \"in_collection\": 379}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 4236993, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"File, FLV, 320\", \"label\": \"RCA\", \"title\": \"One Way Trigger\", \"resource_url\": \"https://api.discogs.com/releases/4236993\", \"role\": \"Main\", \"artist\": \"The Strokes\", \"year\": 2013, \"thumb\": \"https://i.discogs.com/5tc7I6068m03hjdVLaW9s1zr1j-8rImkVoWXWZY9egM/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTQyMzY5/OTMtMTM1OTM0NTMy/OC0zMjE3LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 7, \"in_collection\": 10}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 10229439, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"CDr, Single, Promo\", \"label\": \"RCA, Rough Trade\", \"title\": \"Tap Out\", \"resource_url\": \"https://api.discogs.com/releases/10229439\", \"role\": \"Main\", \"artist\": \"The Strokes\", \"year\": 2013, \"thumb\": \"https://i.discogs.com/2N4U5ReV6zrh2uTVNXHo16VTEPjxVeqhJjdePau27-o/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTEwMjI5/NDM5LTE0OTM3NjQ1/NzQtOTk5My5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 29, \"in_collection\": 12}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 20794279, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"46xFile, WAV, Comp, RE\", \"label\": \"RCA Records Label\", \"title\": \"The Collection\", \"resource_url\": \"https://api.discogs.com/releases/20794279\", \"role\": \"Main\", \"artist\": \"The Strokes\", \"year\": 2013, \"thumb\": \"https://i.discogs.com/7WMe7hkXYXHOnzkpCrPZVbtVKDrvxJkLmcDiZXk272o/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTIwNzk0/Mjc5LTE2MzU2Njky/MjgtOTU3OC5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 15, \"in_collection\": 2}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 537613, \"title\": \"Comedown Machine\", \"type\": \"master\", \"main_release\": 4417538, \"artist\": \"The Strokes\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/537613\", \"year\": 2013, \"thumb\": \"https://i.discogs.com/FgbylAyCGtC0K9wuFuhCNCGlcR6FilhkhXtUnirYGC4/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTQ0MTc1/MzgtMTM2NDMyNjAx/My0yMDYzLmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 391, \"in_collection\": 1208}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 549646, \"title\": \"All The Time\", \"type\": \"master\", \"main_release\": 4812633, \"artist\": \"The Strokes\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/549646\", \"year\": 2013, \"thumb\": \"https://i.discogs.com/0lhYRhluImZR1GECSHZIlAh3yy2d6G6CNTLpZ0E_r6U/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTQ4MTI2/MzMtMTM3NjUwMTkz/Ni01MTI0LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 128, \"in_collection\": 223}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 1009914, \"title\": \"Future Present Past EP\", \"type\": \"master\", \"main_release\": 8600976, \"artist\": \"The Strokes\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/1009914\", \"year\": 2016, \"thumb\": \"https://i.discogs.com/O4GOk4e7r6DAWEzxurb3CyZBgtbcvsCK8oqKZcTenho/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTg2MDA5/NzYtMTQ2NDg4MzUw/Ni05MzEzLmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 953, \"in_collection\": 2771}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 15078464, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"File, MP3, Single, 320\", \"label\": \"RCA\", \"title\": \"Bad Decisions\", \"resource_url\": \"https://api.discogs.com/releases/15078464\", \"role\": \"Main\", \"artist\": \"The Strokes\", \"year\": 2020, \"thumb\": \"https://i.discogs.com/K0_s1UDgOlbOGKbQfKCM1SHZPQQ_rW2V60-sqMONlhg/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTE1MDc4/NDY0LTE1ODY0ODA4/NjYtNjM5MC5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 8, \"in_collection\": 1}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 15084147, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"File, MP3, Single, 320\", \"label\": \"RCA Records\", \"title\": \"Brooklyn Bridge To Chorus\", \"resource_url\": \"https://api.discogs.com/releases/15084147\", \"role\": \"Main\", \"artist\": \"The Strokes\", \"year\": 2020, \"thumb\": \"https://i.discogs.com/wGH1M-jm7NsPWNnV6H-Z1VZQP-U4orYDgdO34TSPGw0/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTE1MDg0/MTQ3LTE1ODY0Nzc5/NjQtMjU1Ni5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 8, \"in_collection\": 2}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 16035226, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"CDr, Promo, Smplr\", \"label\": \"Sony Music Japan International Inc.\", \"title\": \"2 Tracks Sampler From The New Abnormal \", \"resource_url\": \"https://api.discogs.com/releases/16035226\", \"role\": \"Main\", \"artist\": \"The Strokes\", \"year\": 2020, \"thumb\": \"https://i.discogs.com/VyIrTudSSDlcLelP8yIW2hlXMXcHRUlIMFucMBbk5Dw/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTE2MDM1/MjI2LTE2MDIyNzA5/NzUtNDA2MC5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 16, \"in_collection\": 5}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 21508051, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"File, MPEG-4 Video\", \"label\": \"RCA Records\", \"title\": \"The Adults Are Talking\", \"resource_url\": \"https://api.discogs.com/releases/21508051\", \"role\": \"Main\", \"artist\": \"The Strokes\", \"year\": 2020, \"thumb\": \"https://i.discogs.com/h8pXT185YIjo3LPKu0sWPusjGMPJU7gcM-nIH1E0TYE/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTIxNTA4/MDUxLTE2NDA2NDQ5/NzItNDQ3MS5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 0, \"in_collection\": 0}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}]}"
  },
  {
    "path": "test-e2e/hars/a8763b95c9f6c98156a9100e8bed82cb17b93ecd.json",
    "content": "{\"pagination\": {\"page\": 1, \"pages\": 8, \"per_page\": 50, \"items\": 386, \"urls\": {\"last\": \"https://api.discogs.com/artists/391170/releases?token=QBRmstCkwXEvCjTclCpumbtNwvVkEzGAdELXyRyW&page=8&per_page=50\", \"next\": \"https://api.discogs.com/artists/391170/releases?token=QBRmstCkwXEvCjTclCpumbtNwvVkEzGAdELXyRyW&page=2&per_page=50\"}}, \"releases\": [{\"id\": 3668472, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"DVDr\", \"label\": \"Domino\", \"title\": \"Untitled Session\", \"resource_url\": \"https://api.discogs.com/releases/3668472\", \"role\": \"Main\", \"artist\": \"Arctic Monkeys\", \"year\": 2004, \"thumb\": \"https://i.discogs.com/5karLFUrKYitBRl4ZjL2iX632feMgMT8aF1-NSiEuBI/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTM2Njg0/NzItMTMzOTYwMDYy/Ni0yMDE1LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 46, \"in_collection\": 3}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 2364804, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"CDr\", \"label\": \"Domino\", \"title\": \"Untitled\", \"resource_url\": \"https://api.discogs.com/releases/2364804\", \"role\": \"Main\", \"artist\": \"Arctic Monkeys\", \"year\": 2005, \"thumb\": \"https://i.discogs.com/YZhJOAguqfNVuv226iKNF3LKfqBePoZ31fyPegsYbxE/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTIzNjQ4/MDQtMTI3OTczODMy/Mi5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 60, \"in_collection\": 4}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 2367377, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"CDr, Promo\", \"label\": \"Domino\", \"title\": \"Beat 106 Session\", \"resource_url\": \"https://api.discogs.com/releases/2367377\", \"role\": \"Main\", \"artist\": \"Arctic Monkeys\", \"year\": 2005, \"thumb\": \"https://i.discogs.com/ICXFP_tSFIl4isTNu4rZO9hElZmF9V_p_73TA99fLfM/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTIzNjcz/NzctMTI3OTg5Mzg1/Mi5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 51, \"in_collection\": 36}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 2544668, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"CDr, Single, Promo\", \"label\": \"Domino\", \"title\": \"Bigger Boys And Stolen Sweethearts\", \"resource_url\": \"https://api.discogs.com/releases/2544668\", \"role\": \"Main\", \"artist\": \"Arctic Monkeys\", \"year\": 2005, \"thumb\": \"https://i.discogs.com/ybT_Kt2U96cbvDfC0t60Wr3T74ZpG7oC9z6gzc6g7Ps/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTI1NDQ2/NjgtMTI4OTc0Mzkw/Ny5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 63, \"in_collection\": 26}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 2559718, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"DVDr, Promo\", \"label\": \"Domino\", \"title\": \"Later... With Jools Holland (Live)\", \"resource_url\": \"https://api.discogs.com/releases/2559718\", \"role\": \"Main\", \"artist\": \"Arctic Monkeys\", \"year\": 2005, \"thumb\": \"https://i.discogs.com/J_rMUk67xrDm7SvBCc57Qxs1Y9Xk84BYzADVHGvsm9E/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTI1NTk3/MTgtMTMwMDc0MTM0/OS5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 48, \"in_collection\": 3}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 11354539, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"CDr, Promo\", \"label\": \"Not On Label\", \"title\": \"Arctic Monkeys\", \"resource_url\": \"https://api.discogs.com/releases/11354539\", \"role\": \"Main\", \"artist\": \"Arctic Monkeys\", \"year\": 2005, \"thumb\": \"https://i.discogs.com/u-FqpSi4F9uLI2e-JGmT5Hst7y--fFVzxX33H-RK9eI/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTExMzU0/NTM5LTE1MTQ4Mjc5/MjMtMzU1Ny5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 63, \"in_collection\": 10}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 15835270, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"DVDr, DVD-V, Promo, PAL\", \"label\": \"EMI Music Greece\", \"title\": \"2 Trk Promo DVD\", \"resource_url\": \"https://api.discogs.com/releases/15835270\", \"role\": \"Main\", \"artist\": \"Arctic Monkeys\", \"year\": 2005, \"thumb\": \"https://i.discogs.com/ONIngpsB0gekh4IBbQWVYMFCI7-5197U00VmILD8PqQ/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTE1ODM1/MjcwLTE1OTg2NzEx/MTgtNDI1Mi5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 14, \"in_collection\": 2}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 76288, \"title\": \"I Bet You Look Good On The Dancefloor\", \"type\": \"master\", \"main_release\": 555653, \"artist\": \"Arctic Monkeys\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/76288\", \"year\": 2005, \"thumb\": \"https://i.discogs.com/U5SibfMJENDvMGp7RTkjm9HXdyp5muX_CISK3fKvrHg/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTU1NTY1/My0xMjg5NzcwMjk2/LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 1527, \"in_collection\": 2728}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 2953873, \"title\": \"Demo Compilation\", \"type\": \"master\", \"main_release\": 15835194, \"artist\": \"Arctic Monkeys\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/2953873\", \"year\": 2005, \"thumb\": \"https://i.discogs.com/023mQxsE1p9Vzi_sI4KTxRhk9k-VAgRUTEtrygDEJ6I/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTE1ODM1/MTk0LTE1OTg2Njg1/MDMtNjg4Ny5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 30, \"in_collection\": 7}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 98532, \"title\": \"When The Sun Goes Down\", \"type\": \"master\", \"main_release\": 612215, \"artist\": \"Arctic Monkeys\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/98532\", \"year\": 2005, \"thumb\": \"https://i.discogs.com/7FZ6nwaLW6lHPvl9CdKIz-VWOCoNBt9qfCSd6EOu22o/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTYxMjIx/NS0xMzM1MzQ4MjYw/LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 978, \"in_collection\": 2649}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 98535, \"title\": \"Fake Tales Of San Francisco\", \"type\": \"master\", \"main_release\": 3381012, \"artist\": \"Arctic Monkeys\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/98535\", \"year\": 2005, \"thumb\": \"https://i.discogs.com/6U3qlioexI2xd4brVR7rXirzjctxWhqDD2AQbkHGzcw/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTMzODEw/MTItMTMyODE1NTkz/NC5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 57, \"in_collection\": 24}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 76279, \"title\": \"Whatever People Say I Am, That's What I'm Not\", \"type\": \"master\", \"main_release\": 612972, \"artist\": \"Arctic Monkeys\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/76279\", \"year\": 2005, \"thumb\": \"https://i.discogs.com/P-dGTjhMh5-tL-T7vrhnr1DdVUKwLbOrKPSXhKyLdXI/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTYxMjk3/Mi0xNDAxMTgyOTYz/LTczMjIuanBlZw.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 8718, \"in_collection\": 22462}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 76281, \"title\": \"Five Minutes With Arctic Monkeys\", \"type\": \"master\", \"main_release\": 790894, \"artist\": \"Arctic Monkeys\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/76281\", \"year\": 2005, \"thumb\": \"https://i.discogs.com/_e7iKufM91sFimmIogyORJS4rBQ26pCCGpoA5H-46_E/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTc5MDg5/NC0xNTQ5OTExOTky/LTgyODguanBlZw.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 1267, \"in_collection\": 497}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 1836631, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"CDr, Single, Copy Prot., Promo\", \"label\": \"Universal Music TV\", \"title\": \"Dancin Shoes\", \"resource_url\": \"https://api.discogs.com/releases/1836631\", \"role\": \"Main\", \"artist\": \"Rhythms Del Mundo / Arctic Monkeys\", \"year\": 2006, \"thumb\": \"https://i.discogs.com/ZUuOBK0Og3CsQ1_NVnGtx3ym8dM_nqKyEfrTK3XVoVk/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTE4MzY2/MzEtMTMwMDkwNzM4/Mi5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 32, \"in_collection\": 5}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 2544606, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"CDr, Promo\", \"label\": \"Domino\", \"title\": \"Electronic Press Kit - Audio\", \"resource_url\": \"https://api.discogs.com/releases/2544606\", \"role\": \"Main\", \"artist\": \"Arctic Monkeys\", \"year\": 2006, \"thumb\": \"https://i.discogs.com/fxWphsZFAyziM62ExDOVHOznnzfbcuUbJeiXu2jhmWs/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTI1NDQ2/MDYtMTI4OTc0MTI5/Ni5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 22, \"in_collection\": 23}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 2602007, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"DVDr, Promo\", \"label\": \"Domino\", \"title\": \"@ Astoria\", \"resource_url\": \"https://api.discogs.com/releases/2602007\", \"role\": \"Main\", \"artist\": \"Arctic Monkeys\", \"year\": 2006, \"thumb\": \"https://i.discogs.com/Ck0Phzl-9YQQETEUoJ35Oe--_oGd7FFy7dI1WW4KOio/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTI2MDIw/MDctMTI5OTUzMzgx/My5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 33, \"in_collection\": 3}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 4085497, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"CDr, Single, Promo\", \"label\": \"Domino\", \"title\": \"Baby I'm Yours\", \"resource_url\": \"https://api.discogs.com/releases/4085497\", \"role\": \"Main\", \"artist\": \"Arctic Monkeys\", \"year\": 2006, \"thumb\": \"https://i.discogs.com/dzJDO-Ng8ewrXXjTZ5HEwlB63o_bsXbLcmxUBhxCwNI/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTQwODU0/OTctMTM2MjE2NjU5/OC0zNzI5LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 62, \"in_collection\": 6}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 17328361, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"CDr, Single, Promo\", \"label\": \"Domino\", \"title\": \"Cigarette Smoke\", \"resource_url\": \"https://api.discogs.com/releases/17328361\", \"role\": \"Main\", \"artist\": \"Arctic Monkeys\", \"year\": 2006, \"thumb\": \"https://i.discogs.com/-u-B53vR8T2PvzjeonS6upai4SKmtZEP0zOyM7UmH_w/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTE3MzI4/MzYxLTE2MTI4MzY3/OTQtMTM3Ni5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 35, \"in_collection\": 2}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 17709277, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"DVDr, Promo\", \"label\": \"Domino\", \"title\": \"EPK - DVD\", \"resource_url\": \"https://api.discogs.com/releases/17709277\", \"role\": \"Main\", \"artist\": \"Arctic Monkeys\", \"year\": 2006, \"thumb\": \"https://i.discogs.com/t9ffUffdVKGezaxI06NPP1Iu7v8QYyYMNHD2itYzMlQ/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTE3NzA5/Mjc3LTE2MTQ5ODEz/MDUtMTgwMS5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 13, \"in_collection\": 1}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 30157721, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"DVDr, Promo\", \"label\": \"Domino\", \"title\": \"EPK - Colour & Black & White Version\", \"resource_url\": \"https://api.discogs.com/releases/30157721\", \"role\": \"Main\", \"artist\": \"Arctic Monkeys\", \"year\": 2006, \"thumb\": \"https://i.discogs.com/FEb8-YOeAoqV77rPNCvbrRm7xsyPmvy5dgf1s65c2AA/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTMwMTU3/NzIxLTE3MTA5ODI5/MjYtNjAyNy5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 7, \"in_collection\": 1}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 93220, \"title\": \"Who The Fuck Are Arctic Monkeys?\", \"type\": \"master\", \"main_release\": 695957, \"artist\": \"Arctic Monkeys\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/93220\", \"year\": 2006, \"thumb\": \"https://i.discogs.com/Z0vOxYCl306mG5jD5_CT1L-TFozZBFCRTF6_9FIwdiw/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTY5NTk1/Ny0xNTA2MDY2Nzk5/LTMxMzAuanBlZw.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 1900, \"in_collection\": 6873}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 93240, \"title\": \"Leave Before The Lights Come On\", \"type\": \"master\", \"main_release\": 760159, \"artist\": \"Arctic Monkeys\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/93240\", \"year\": 2006, \"thumb\": \"https://i.discogs.com/PMQVy6FzjRWKVApea8LJl3EsBuBdt509-MHjRasYXdk/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTc2MDE1/OS0xMjg5NzQ5NjIz/LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 1361, \"in_collection\": 2048}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 249924, \"title\": \"Scummy Man\", \"type\": \"master\", \"main_release\": 1146577, \"artist\": \"Arctic Monkeys\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/249924\", \"year\": 2006, \"thumb\": \"https://i.discogs.com/ggBOlgW1Ts_YaecTP3CaJkOPSk830FQX5jj9f8jS3KM/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTExNDY1/NzctMTE5NTg2NzQ4/Ny5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 60, \"in_collection\": 562}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 616735, \"title\": \"The View From The Afternoon\", \"type\": \"master\", \"main_release\": 1973747, \"artist\": \"Arctic Monkeys\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/616735\", \"year\": 2006, \"thumb\": \"https://i.discogs.com/hWZbl0sbqoUmZyren-9GFlp59YO7-RUrlbcs3Iy_05k/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTE5NzM3/NDctMTI4Njk4NjMx/Mi5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 97, \"in_collection\": 139}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 262621, \"title\": \"Live In Texas - 7 June 2006\", \"type\": \"master\", \"main_release\": 5547852, \"artist\": \"Arctic Monkeys\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/262621\", \"year\": 2006, \"thumb\": \"https://i.discogs.com/GxKcVmHNcKAewhtVd0P164Osu1Yf88iFTZ13CFIH2XY/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTU1NDc4/NTItMTcxNzU5OTY2/Mi03Mjc1LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 1042, \"in_collection\": 450}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 2602796, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"CDr, Promo\", \"label\": \"Domino\", \"title\": \"Radio Session\", \"resource_url\": \"https://api.discogs.com/releases/2602796\", \"role\": \"Main\", \"artist\": \"Arctic Monkeys\", \"year\": 2007, \"thumb\": \"https://i.discogs.com/1UWI3zu8jK2uoPKdnH_AG9pzzPaNzWOVyaP3yEtPAtE/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTI2MDI3/OTYtMTI5MjY4NTE3/My5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 65, \"in_collection\": 10}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 2753854, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"CDr, Promo\", \"label\": \"Domino\", \"title\": \"2 Track For Mix FM (Acoustic)\", \"resource_url\": \"https://api.discogs.com/releases/2753854\", \"role\": \"Main\", \"artist\": \"Arctic Monkeys\", \"year\": 2007, \"thumb\": \"https://i.discogs.com/ZSjXMqoO6qRTZpj9Tyq7hJK89ks9VOlELPGiO4PEqS0/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTI3NTM4/NTQtMTI5OTUxNDY4/Ni5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 42, \"in_collection\": 6}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 4986302, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"CDr, Single, Promo\", \"label\": \"Domino\", \"title\": \"This House Is A Circus (Clean Version)\", \"resource_url\": \"https://api.discogs.com/releases/4986302\", \"role\": \"Main\", \"artist\": \"Arctic Monkeys\", \"year\": 2007, \"thumb\": \"https://i.discogs.com/MoLN6UWPYot60HiBjv9pZjA680qu-i5mN4P24nrhlss/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTQ5ODYz/MDItMTM4MTQxMDg1/MS05NTI3LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 37, \"in_collection\": 9}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 8502514, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"DVD-V\", \"label\": \"Edgehill Publishing Ltd\", \"title\": \"The Arctic Monkeys Phenomenon Behind The Music\", \"resource_url\": \"https://api.discogs.com/releases/8502514\", \"role\": \"Main\", \"artist\": \"Arctic Monkeys\", \"year\": 2007, \"thumb\": \"https://i.discogs.com/SPb0WwqmAjCK8Tu0yCnTDvJjArGM1h-yh652CveQUds/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTg1MDI1/MTQtMTQ2MjkwMTg0/MC02MDY5LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 23, \"in_collection\": 26}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 31464239, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"CD, Album, Jew\", \"label\": \"Domino Recording Co. Ltd.\", \"title\": \"Favourite Worst Nightmare\", \"resource_url\": \"https://api.discogs.com/releases/31464239\", \"role\": \"Main\", \"artist\": \"Arctic Monkeys\", \"year\": 2007, \"thumb\": \"https://i.discogs.com/lH2atPWQ-AGO1Az10UnCJdirNBheMceoFehXgNTHRFQ/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTMxNDY0/MjM5LTE3MjM0ODg4/OTUtOTE3MC5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 0, \"in_collection\": 1}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 93234, \"title\": \"Fluorescent Adolescent\", \"type\": \"master\", \"main_release\": 1010314, \"artist\": \"Arctic Monkeys\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/93234\", \"year\": 2007, \"thumb\": \"https://i.discogs.com/JGe6G4Pz1nX272U9F7W4x5tzON1dV6UXACb-enRImS4/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTEwMTAz/MTQtMTU1NTM0OTQ3/OC02NTgxLmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 950, \"in_collection\": 1653}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 93235, \"title\": \"Teddy Picker\", \"type\": \"master\", \"main_release\": 1160710, \"artist\": \"Arctic Monkeys\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/93235\", \"year\": 2007, \"thumb\": \"https://i.discogs.com/bcNRawGyCAecZicvWb9C59iKZK8hvh3MCtzYjbwRIAo/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTExNjA3/MTAtMTI4OTc3MDY4/Mi5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 547, \"in_collection\": 1224}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 2385481, \"title\": \"Matador / Daframe2r\", \"type\": \"master\", \"main_release\": 1000497, \"artist\": \"Arctic Monkeys\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/2385481\", \"year\": 2007, \"thumb\": \"https://i.discogs.com/F-voB5nhHQ3t9Okp59Id6WWmRpXwzQ2J6pdNB7ZkE9Y/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTEwMDA0/OTctMTM1ODc1Mjc4/NS00MjY5LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 898, \"in_collection\": 1855}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 69774, \"title\": \"Favourite Worst Nightmare\", \"type\": \"master\", \"main_release\": 956134, \"artist\": \"Arctic Monkeys\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/69774\", \"year\": 2007, \"thumb\": \"https://i.discogs.com/utvFBspdVrQxUtqNhh24GEc8YvZ98rKtKShvokPVaDs/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTk1NjEz/NC0xMTc3ODQ5MzEw/LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 1296, \"in_collection\": 7290}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 1168704, \"title\": \"In Concert 1008\", \"type\": \"master\", \"main_release\": 24500075, \"artist\": \"Arctic Monkeys\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/1168704\", \"year\": 2007, \"thumb\": \"https://i.discogs.com/6rshq_4oRkkHb4B0Ld8XPba4caneVwrwg8vkEdfjoD8/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTI0NTAw/MDc1LTE2NjMwNjcy/NTQtMjQ0Mi5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 30, \"in_collection\": 2}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 76285, \"title\": \"Brianstorm\", \"type\": \"master\", \"main_release\": 959102, \"artist\": \"Arctic Monkeys\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/76285\", \"year\": 2007, \"thumb\": \"https://i.discogs.com/9aDtwD1fbe3GG6VxAXjHKbdgfW0vx8ytiqgdVE2Dpxk/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTk1OTEw/Mi0xNTU1MzUwOTQz/LTI1MzIuanBlZw.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 620, \"in_collection\": 1807}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 185042, \"title\": \"At The Apollo\", \"type\": \"master\", \"main_release\": 3585319, \"artist\": \"Arctic Monkeys\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/185042\", \"year\": 2008, \"thumb\": \"https://i.discogs.com/JFHb350hF-mbVk0fJnG70DHKqX7C1ru7iXUj3TxF42U/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTM1ODUz/MTktMTM0NDA5NTc5/Ny00NzA3LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 57, \"in_collection\": 430}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 723806, \"title\": \"LateNightTales\", \"type\": \"master\", \"main_release\": 1684044, \"artist\": \"Arctic Monkeys\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/723806\", \"year\": 2008, \"thumb\": \"https://i.discogs.com/xB0wsSSZ3yorBF5iCGmz-068_hSgPl9GAJb0SLisfuI/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTE2ODQw/NDQtMTMzNjEzNTA2/MS5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 140, \"in_collection\": 337}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 2316130, \"title\": \"At The Apollo / Live In Texas - 7 June 2006\", \"type\": \"master\", \"main_release\": 1554146, \"artist\": \"Arctic Monkeys\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/2316130\", \"year\": 2008, \"thumb\": \"https://i.discogs.com/dTN9PIrjlgmDae9ItBxV-yo-gSJlzJ2CZt3gueZZuLo/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTE1NTQx/NDYtMTcyMjA5Mzg4/MC0yNzI0LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 600, \"in_collection\": 1206}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 2367397, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"CD, Promo\", \"label\": \"Domino, KEXP\", \"title\": \"Radiosession\", \"resource_url\": \"https://api.discogs.com/releases/2367397\", \"role\": \"Main\", \"artist\": \"Arctic Monkeys\", \"year\": 2009, \"thumb\": \"https://i.discogs.com/3-zUXzuh9-C-9QRQGMjC4K4OJ2fBeAEA_q2ww8JkTWk/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTIzNjcz/OTctMTI3OTg5NDI5/OS5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 60, \"in_collection\": 56}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 198949, \"title\": \"Cornerstone\", \"type\": \"master\", \"main_release\": 1997270, \"artist\": \"Arctic Monkeys\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/198949\", \"year\": 2009, \"thumb\": \"https://i.discogs.com/QGC8ddmM5mA_rLxdjSg7F1_7ebE8LcKwbF4vb1fWqz4/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTE5OTcy/NzAtMTI4NzA3ODMy/MS5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 621, \"in_collection\": 1046}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 172482, \"title\": \"Humbug\", \"type\": \"master\", \"main_release\": 1895502, \"artist\": \"Arctic Monkeys\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/172482\", \"year\": 2009, \"thumb\": \"https://i.discogs.com/samjxfXjFOmqZ1sRadd4zpY-0MHIcrYMuTJ6JcR1LjE/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTE4OTU1/MDItMTM5OTE5NzM1/My05NDgyLmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 3503, \"in_collection\": 10605}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 172483, \"title\": \"Crying Lightning\", \"type\": \"master\", \"main_release\": 1893489, \"artist\": \"Arctic Monkeys\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/172483\", \"year\": 2009, \"thumb\": \"https://i.discogs.com/ZdxHbcIMApat5eJrJypW-ErcC4mhNcYCw-CFd8GC_iQ/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTE4OTM0/ODktMTI4NzA3Nzky/Ni5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 695, \"in_collection\": 1877}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 236044, \"title\": \"My Propeller\", \"type\": \"master\", \"main_release\": 2190659, \"artist\": \"Arctic Monkeys\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/236044\", \"year\": 2010, \"thumb\": \"https://i.discogs.com/BppJumdhw86a-gnbmRHmgz7HsB0Tbvk3j70hxfSsstc/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTIxOTA2/NTktMTI4Njk4NTky/OS5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 437, \"in_collection\": 815}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 6943626, \"status\": \"Accepted\", \"type\": \"release\", \"format\": \"6xFile, AAC, EP, 256\", \"label\": \"Domino\", \"title\": \"iTunes Festival: London 2011\", \"resource_url\": \"https://api.discogs.com/releases/6943626\", \"role\": \"Main\", \"artist\": \"Arctic Monkeys\", \"year\": 2011, \"thumb\": \"https://i.discogs.com/qMYQ8pdQpAoGvqEukx7fu-OQzGo-fLZ5DNfVypOhDsk/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTY5NDM2/MjYtMTY2Nzk2MjE4/OC0xODA4LmpwZWc.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 21, \"in_collection\": 26}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 341083, \"title\": \"Suck It And See\", \"type\": \"master\", \"main_release\": 2915645, \"artist\": \"Arctic Monkeys\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/341083\", \"year\": 2011, \"thumb\": \"https://i.discogs.com/hbjpTUZIEpX0fSCz6P4ykJvuyQLgT5hb8SPsUd9OxP8/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTI5MTU2/NDUtMTMwOTk3OTIw/NS5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 550, \"in_collection\": 3542}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 378466, \"title\": \"The Hellcat Spangled Shalalala\", \"type\": \"master\", \"main_release\": 3044583, \"artist\": \"Arctic Monkeys\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/378466\", \"year\": 2011, \"thumb\": \"https://i.discogs.com/RBOCwjn4z2F9SI_NoCz-YQV22OrWrtr6cX7kba6o2FM/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTMwNDQ1/ODMtMTMzNjE4Mzc4/NC5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 669, \"in_collection\": 934}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 437414, \"title\": \"Suck It And See\", \"type\": \"master\", \"main_release\": 3196546, \"artist\": \"Arctic Monkeys\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/437414\", \"year\": 2011, \"thumb\": \"https://i.discogs.com/JzYjH4lqcgt9puh2QfPMslh9ezC1Yd6oxhOuMiWzDUw/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTMxOTY1/NDYtMTMyNTAyNTM1/NC5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 731, \"in_collection\": 1051}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 407318, \"title\": \"Black Treacle\", \"type\": \"master\", \"main_release\": 3357793, \"artist\": \"Arctic Monkeys\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/407318\", \"year\": 2011, \"thumb\": \"https://i.discogs.com/7YUpAp63aovIRP9HeFu1YT2BqH8ACyZjkYrk32T4pIs/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTMzNTc3/OTMtMTMyNzc2MjE3/My5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 657, \"in_collection\": 1117}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}, {\"id\": 339433, \"title\": \"Don't Sit Down 'Cause I've Moved Your Chair\", \"type\": \"master\", \"main_release\": 2903217, \"artist\": \"Arctic Monkeys\", \"role\": \"Main\", \"resource_url\": \"https://api.discogs.com/masters/339433\", \"year\": 2011, \"thumb\": \"https://i.discogs.com/NPd_sTJRgL4_U-uivgUOqk9x0TRk27IhmiMKooyPj2o/rs:fit/g:sm/q:40/h:150/w:150/czM6Ly9kaXNjb2dz/LWRhdGFiYXNlLWlt/YWdlcy9SLTI5MDMy/MTctMTMwNjg0NzEz/My5qcGVn.jpeg\", \"stats\": {\"community\": {\"in_wantlist\": 401, \"in_collection\": 945}, \"user\": {\"in_wantlist\": 0, \"in_collection\": 0}}}]}"
  },
  {
    "path": "test-e2e/hars/discogs.har",
    "content": "{\n  \"log\": {\n    \"version\": \"1.2\",\n    \"creator\": {\n      \"name\": \"Playwright\",\n      \"version\": \"1.46.0\"\n    },\n    \"browser\": {\n      \"name\": \"firefox\",\n      \"version\": \"128.0\"\n    },\n    \"entries\": [\n      {\n        \"startedDateTime\": \"2024-08-21T17:20:40.774Z\",\n        \"time\": 0.42,\n        \"request\": {\n          \"method\": \"GET\",\n          \"url\": \"https://api.discogs.com/artists/55980/releases?token=QBRmstCkwXEvCjTclCpumbtNwvVkEzGAdELXyRyW\",\n          \"httpVersion\": \"HTTP/2.0\",\n          \"cookies\": [],\n          \"headers\": [\n            { \"name\": \"Host\", \"value\": \"api.discogs.com\" },\n            { \"name\": \"User-Agent\", \"value\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0\" },\n            { \"name\": \"Accept\", \"value\": \"*/*\" },\n            { \"name\": \"Accept-Language\", \"value\": \"en-US\" },\n            { \"name\": \"Accept-Encoding\", \"value\": \"gzip, deflate, br, zstd\" },\n            { \"name\": \"Referer\", \"value\": \"http://localhost:3001/\" },\n            { \"name\": \"Origin\", \"value\": \"http://localhost:3001\" },\n            { \"name\": \"Sec-Fetch-Dest\", \"value\": \"empty\" },\n            { \"name\": \"Sec-Fetch-Mode\", \"value\": \"cors\" },\n            { \"name\": \"Sec-Fetch-Site\", \"value\": \"cross-site\" },\n            { \"name\": \"Connection\", \"value\": \"keep-alive\" }\n          ],\n          \"queryString\": [\n            {\n              \"name\": \"token\",\n              \"value\": \"QBRmstCkwXEvCjTclCpumbtNwvVkEzGAdELXyRyW\"\n            }\n          ],\n          \"headersSize\": -1,\n          \"bodySize\": -1\n        },\n        \"response\": {\n          \"status\": 200,\n          \"statusText\": \"\",\n          \"httpVersion\": \"HTTP/2.0\",\n          \"cookies\": [],\n          \"headers\": [\n            { \"name\": \"date\", \"value\": \"Wed\" },\n            { \"name\": \"date\", \"value\": \"21 Aug 2024 17:20:41 GMT\" },\n            { \"name\": \"content-type\", \"value\": \"application/json\" },\n            { \"name\": \"access-control-allow-headers\", \"value\": \"Content-Type\" },\n            { \"name\": \"access-control-allow-headers\", \"value\": \"authorization\" },\n            { \"name\": \"access-control-allow-headers\", \"value\": \"User-Agent\" },\n            { \"name\": \"access-control-allow-headers\", \"value\": \"Private-Auth-Secret\" },\n            { \"name\": \"access-control-allow-headers\", \"value\": \"Discogs-UID\" },\n            { \"name\": \"access-control-allow-methods\", \"value\": \"HEAD\" },\n            { \"name\": \"access-control-allow-methods\", \"value\": \"OPTIONS\" },\n            { \"name\": \"access-control-allow-methods\", \"value\": \"GET\" },\n            { \"name\": \"access-control-allow-methods\", \"value\": \"OPTIONS\" },\n            { \"name\": \"access-control-allow-origin\", \"value\": \"*\" },\n            { \"name\": \"access-control-expose-headers\", \"value\": \"Location\" },\n            { \"name\": \"cache-control\", \"value\": \"public\" },\n            { \"name\": \"cache-control\", \"value\": \"must-revalidate\" },\n            { \"name\": \"content-encoding\", \"value\": \"gzip\" },\n            { \"name\": \"content-language\", \"value\": \"en\" },\n            { \"name\": \"strict-transport-security\", \"value\": \"max-age=15552000\" },\n            { \"name\": \"vary\", \"value\": \"Accept-Encoding\" },\n            { \"name\": \"x-content-type-options\", \"value\": \"nosniff\" },\n            { \"name\": \"x-discogs-media-type\", \"value\": \"discogs.v2\" },\n            { \"name\": \"x-discogs-ratelimit\", \"value\": \"60\" },\n            { \"name\": \"x-discogs-ratelimit-remaining\", \"value\": \"49\" },\n            { \"name\": \"x-discogs-ratelimit-used\", \"value\": \"11\" },\n            { \"name\": \"x-frame-options\", \"value\": \"SAMEORIGIN\" },\n            { \"name\": \"x-xss-protection\", \"value\": \"1; mode=block\" },\n            { \"name\": \"cf-cache-status\", \"value\": \"DYNAMIC\" },\n            { \"name\": \"set-cookie\", \"value\": \"__cf_bm=ZDi6CQO3XdzmMMM8Pys8gSgKxc2yLjCItxB3QMjdGvQ-1724260841-1.0.1.1-kJHfukSic811lZB.Q3I9AHKIJQp1sky_raqNrmrahQ8P1yCDQ9L3RdeIhx0_STgtrsWBPfXP.xbdktI1K3eE.g; path=/; expires=Wed, 21-Aug-24 17:50:41 GMT; domain=.discogs.com; HttpOnly; Secure; SameSite=None\" },\n            { \"name\": \"server\", \"value\": \"cloudflare\" },\n            { \"name\": \"cf-ray\", \"value\": \"8b6c4b8f1c6b8673-PER\" },\n            { \"name\": \"alt-svc\", \"value\": \"h3=\\\":443\\\"; ma=86400\" },\n            { \"name\": \"X-Firefox-Spdy\", \"value\": \"h2\" }\n          ],\n          \"content\": {\n            \"size\": -1,\n            \"mimeType\": \"application/json\",\n            \"_file\": \"69c6136c671f1173ee6d6596d125e821dea44a4f.json\"\n          },\n          \"headersSize\": -1,\n          \"bodySize\": -1,\n          \"redirectURL\": \"\"\n        },\n        \"cache\": {},\n        \"timings\": { \"send\": -1, \"wait\": -1, \"receive\": 0.42 }\n      },\n      {\n        \"startedDateTime\": \"2024-08-21T17:20:40.777Z\",\n        \"time\": 1.026,\n        \"request\": {\n          \"method\": \"GET\",\n          \"url\": \"https://api.discogs.com/artists/391170/releases?token=QBRmstCkwXEvCjTclCpumbtNwvVkEzGAdELXyRyW\",\n          \"httpVersion\": \"HTTP/2.0\",\n          \"cookies\": [],\n          \"headers\": [\n            { \"name\": \"Host\", \"value\": \"api.discogs.com\" },\n            { \"name\": \"User-Agent\", \"value\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0\" },\n            { \"name\": \"Accept\", \"value\": \"*/*\" },\n            { \"name\": \"Accept-Language\", \"value\": \"en-US\" },\n            { \"name\": \"Accept-Encoding\", \"value\": \"gzip, deflate, br, zstd\" },\n            { \"name\": \"Referer\", \"value\": \"http://localhost:3001/\" },\n            { \"name\": \"Origin\", \"value\": \"http://localhost:3001\" },\n            { \"name\": \"Sec-Fetch-Dest\", \"value\": \"empty\" },\n            { \"name\": \"Sec-Fetch-Mode\", \"value\": \"cors\" },\n            { \"name\": \"Sec-Fetch-Site\", \"value\": \"cross-site\" },\n            { \"name\": \"Connection\", \"value\": \"keep-alive\" }\n          ],\n          \"queryString\": [\n            {\n              \"name\": \"token\",\n              \"value\": \"QBRmstCkwXEvCjTclCpumbtNwvVkEzGAdELXyRyW\"\n            }\n          ],\n          \"headersSize\": -1,\n          \"bodySize\": -1\n        },\n        \"response\": {\n          \"status\": 200,\n          \"statusText\": \"\",\n          \"httpVersion\": \"HTTP/2.0\",\n          \"cookies\": [],\n          \"headers\": [\n            { \"name\": \"date\", \"value\": \"Wed\" },\n            { \"name\": \"date\", \"value\": \"21 Aug 2024 17:20:41 GMT\" },\n            { \"name\": \"content-type\", \"value\": \"application/json\" },\n            { \"name\": \"access-control-allow-headers\", \"value\": \"Content-Type\" },\n            { \"name\": \"access-control-allow-headers\", \"value\": \"authorization\" },\n            { \"name\": \"access-control-allow-headers\", \"value\": \"User-Agent\" },\n            { \"name\": \"access-control-allow-headers\", \"value\": \"Private-Auth-Secret\" },\n            { \"name\": \"access-control-allow-headers\", \"value\": \"Discogs-UID\" },\n            { \"name\": \"access-control-allow-methods\", \"value\": \"HEAD\" },\n            { \"name\": \"access-control-allow-methods\", \"value\": \"OPTIONS\" },\n            { \"name\": \"access-control-allow-methods\", \"value\": \"GET\" },\n            { \"name\": \"access-control-allow-methods\", \"value\": \"OPTIONS\" },\n            { \"name\": \"access-control-allow-origin\", \"value\": \"*\" },\n            { \"name\": \"access-control-expose-headers\", \"value\": \"Location\" },\n            { \"name\": \"cache-control\", \"value\": \"public\" },\n            { \"name\": \"cache-control\", \"value\": \"must-revalidate\" },\n            { \"name\": \"content-encoding\", \"value\": \"gzip\" },\n            { \"name\": \"content-language\", \"value\": \"en\" },\n            { \"name\": \"strict-transport-security\", \"value\": \"max-age=15552000\" },\n            { \"name\": \"vary\", \"value\": \"Accept-Encoding\" },\n            { \"name\": \"x-content-type-options\", \"value\": \"nosniff\" },\n            { \"name\": \"x-discogs-media-type\", \"value\": \"discogs.v2\" },\n            { \"name\": \"x-discogs-ratelimit\", \"value\": \"60\" },\n            { \"name\": \"x-discogs-ratelimit-remaining\", \"value\": \"47\" },\n            { \"name\": \"x-discogs-ratelimit-used\", \"value\": \"13\" },\n            { \"name\": \"x-frame-options\", \"value\": \"SAMEORIGIN\" },\n            { \"name\": \"x-xss-protection\", \"value\": \"1; mode=block\" },\n            { \"name\": \"cf-cache-status\", \"value\": \"DYNAMIC\" },\n            { \"name\": \"set-cookie\", \"value\": \"__cf_bm=pnqVAsFhi65aFInB8tzcaOCrIWXqL9cIv1DLWMz1sXQ-1724260841-1.0.1.1-F.1e1E0vBjbywc37e7JDpAtcDmLgposF0ycJA5igIrOnatD10cdRjSR6Xc9NdujFCXTIRta.4.b8HgKsVI_dSg; path=/; expires=Wed, 21-Aug-24 17:50:41 GMT; domain=.discogs.com; HttpOnly; Secure; SameSite=None\" },\n            { \"name\": \"server\", \"value\": \"cloudflare\" },\n            { \"name\": \"cf-ray\", \"value\": \"8b6c4b8f1c6d8673-PER\" },\n            { \"name\": \"alt-svc\", \"value\": \"h3=\\\":443\\\"; ma=86400\" },\n            { \"name\": \"X-Firefox-Spdy\", \"value\": \"h2\" }\n          ],\n          \"content\": {\n            \"size\": -1,\n            \"mimeType\": \"application/json\",\n            \"_file\": \"a8763b95c9f6c98156a9100e8bed82cb17b93ecd.json\"\n          },\n          \"headersSize\": -1,\n          \"bodySize\": -1,\n          \"redirectURL\": \"\"\n        },\n        \"cache\": {},\n        \"timings\": { \"send\": -1, \"wait\": -1, \"receive\": 1.026 }\n      },\n      {\n        \"startedDateTime\": \"2024-08-21T17:20:40.778Z\",\n        \"time\": 1.004,\n        \"request\": {\n          \"method\": \"GET\",\n          \"url\": \"https://api.discogs.com/artists/83080/releases?token=QBRmstCkwXEvCjTclCpumbtNwvVkEzGAdELXyRyW\",\n          \"httpVersion\": \"HTTP/2.0\",\n          \"cookies\": [],\n          \"headers\": [\n            { \"name\": \"Host\", \"value\": \"api.discogs.com\" },\n            { \"name\": \"User-Agent\", \"value\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0\" },\n            { \"name\": \"Accept\", \"value\": \"*/*\" },\n            { \"name\": \"Accept-Language\", \"value\": \"en-US\" },\n            { \"name\": \"Accept-Encoding\", \"value\": \"gzip, deflate, br, zstd\" },\n            { \"name\": \"Referer\", \"value\": \"http://localhost:3001/\" },\n            { \"name\": \"Origin\", \"value\": \"http://localhost:3001\" },\n            { \"name\": \"Sec-Fetch-Dest\", \"value\": \"empty\" },\n            { \"name\": \"Sec-Fetch-Mode\", \"value\": \"cors\" },\n            { \"name\": \"Sec-Fetch-Site\", \"value\": \"cross-site\" },\n            { \"name\": \"Connection\", \"value\": \"keep-alive\" }\n          ],\n          \"queryString\": [\n            {\n              \"name\": \"token\",\n              \"value\": \"QBRmstCkwXEvCjTclCpumbtNwvVkEzGAdELXyRyW\"\n            }\n          ],\n          \"headersSize\": -1,\n          \"bodySize\": -1\n        },\n        \"response\": {\n          \"status\": 200,\n          \"statusText\": \"\",\n          \"httpVersion\": \"HTTP/2.0\",\n          \"cookies\": [],\n          \"headers\": [\n            { \"name\": \"date\", \"value\": \"Wed\" },\n            { \"name\": \"date\", \"value\": \"21 Aug 2024 17:20:41 GMT\" },\n            { \"name\": \"content-type\", \"value\": \"application/json\" },\n            { \"name\": \"access-control-allow-headers\", \"value\": \"Content-Type\" },\n            { \"name\": \"access-control-allow-headers\", \"value\": \"authorization\" },\n            { \"name\": \"access-control-allow-headers\", \"value\": \"User-Agent\" },\n            { \"name\": \"access-control-allow-headers\", \"value\": \"Private-Auth-Secret\" },\n            { \"name\": \"access-control-allow-headers\", \"value\": \"Discogs-UID\" },\n            { \"name\": \"access-control-allow-methods\", \"value\": \"HEAD\" },\n            { \"name\": \"access-control-allow-methods\", \"value\": \"OPTIONS\" },\n            { \"name\": \"access-control-allow-methods\", \"value\": \"GET\" },\n            { \"name\": \"access-control-allow-methods\", \"value\": \"OPTIONS\" },\n            { \"name\": \"access-control-allow-origin\", \"value\": \"*\" },\n            { \"name\": \"access-control-expose-headers\", \"value\": \"Location\" },\n            { \"name\": \"cache-control\", \"value\": \"public\" },\n            { \"name\": \"cache-control\", \"value\": \"must-revalidate\" },\n            { \"name\": \"content-encoding\", \"value\": \"gzip\" },\n            { \"name\": \"content-language\", \"value\": \"en\" },\n            { \"name\": \"strict-transport-security\", \"value\": \"max-age=15552000\" },\n            { \"name\": \"vary\", \"value\": \"Accept-Encoding\" },\n            { \"name\": \"x-content-type-options\", \"value\": \"nosniff\" },\n            { \"name\": \"x-discogs-media-type\", \"value\": \"discogs.v2\" },\n            { \"name\": \"x-discogs-ratelimit\", \"value\": \"60\" },\n            { \"name\": \"x-discogs-ratelimit-remaining\", \"value\": \"48\" },\n            { \"name\": \"x-discogs-ratelimit-used\", \"value\": \"12\" },\n            { \"name\": \"x-frame-options\", \"value\": \"SAMEORIGIN\" },\n            { \"name\": \"x-xss-protection\", \"value\": \"1; mode=block\" },\n            { \"name\": \"cf-cache-status\", \"value\": \"DYNAMIC\" },\n            { \"name\": \"set-cookie\", \"value\": \"__cf_bm=z1ZzMTDjlYia15YJNRnkk263WppEbjUeTpA1zMagLII-1724260841-1.0.1.1-jmF.JtZUZBHELgzsk9NsAU4gsbeMA7wazCGrpNB0SVsrwFvnFfGxlGtcMVbLpypAioPpTeIlYfEE.dM4wfctmg; path=/; expires=Wed, 21-Aug-24 17:50:41 GMT; domain=.discogs.com; HttpOnly; Secure; SameSite=None\" },\n            { \"name\": \"server\", \"value\": \"cloudflare\" },\n            { \"name\": \"cf-ray\", \"value\": \"8b6c4b8f1c6e8673-PER\" },\n            { \"name\": \"alt-svc\", \"value\": \"h3=\\\":443\\\"; ma=86400\" },\n            { \"name\": \"X-Firefox-Spdy\", \"value\": \"h2\" }\n          ],\n          \"content\": {\n            \"size\": -1,\n            \"mimeType\": \"application/json\",\n            \"_file\": \"0432285dab6a62ab5e6efaf4cb1272720e0c3f1b.json\"\n          },\n          \"headersSize\": -1,\n          \"bodySize\": -1,\n          \"redirectURL\": \"\"\n        },\n        \"cache\": {},\n        \"timings\": { \"send\": -1, \"wait\": -1, \"receive\": 1.004 }\n      }\n    ]\n  }\n}"
  },
  {
    "path": "test-e2e/select-test-suit.ts",
    "content": "import { expect, type Locator, type Page } from '@playwright/test';\nimport { TestSuit } from './test-suit';\n\nexport class SelectTestSuit extends TestSuit {\n  readonly wrappedSelect: Locator;\n\n  readonly choices: Locator;\n\n  readonly selectableChoices: Locator;\n\n  readonly itemsWithPlaceholder: Locator;\n\n  constructor(page: Page, choicesBundle: string | undefined, url: string, testId: string) {\n    super(page, choicesBundle, url, testId);\n\n    this.wrappedSelect = this.group.locator('select');\n    this.choices = this.dropdown.locator('.choices__item');\n    this.selectableChoices = this.dropdown.locator('.choices__item:not(.choices__placeholder):not(.choices__notice)');\n    this.itemsWithPlaceholder = this.itemList.locator('.choices__item');\n  }\n\n  async startWithClick(): Promise<void> {\n    await this.start();\n    await this.selectByClick();\n    await this.expectVisibleDropdown();\n  }\n\n  async delayData(): Promise<() => void> {\n    let stopJsonWaiting = (): void => {};\n    const jsonWaiting = new Promise<void>((f) => {\n      stopJsonWaiting = f;\n    });\n\n    await this.page.route('**/data.json', async (route) => {\n      await jsonWaiting;\n\n      const fakeData = [...new Array(10)].map((_, index) => ({\n        label: `Label ${index + 1}`,\n        value: `Value ${index + 1}`,\n      }));\n\n      await route.fulfill({\n        status: 200,\n        contentType: 'application/json',\n        body: JSON.stringify(fakeData),\n      });\n    });\n\n    return stopJsonWaiting;\n  }\n\n  async delayDisaabledData(): Promise<() => void> {\n    let stopJsonWaiting = (): void => {};\n    const jsonWaiting = new Promise<void>((f) => {\n      stopJsonWaiting = f;\n    });\n\n    await this.page.route('**/disabled-data.json', async (route) => {\n      await jsonWaiting;\n\n      const fakeData = [...new Array(10)].map((_, index) => ({\n        label: `Disabled Label ${index + 1}`,\n        value: `Disabled Value ${index + 1}`,\n        disabled: true,\n      }));\n\n      await route.fulfill({\n        status: 200,\n        contentType: 'application/json',\n        body: JSON.stringify(fakeData),\n      });\n    });\n\n    return stopJsonWaiting;\n  }\n\n  getWrappedElement(): Locator {\n    return this.wrappedSelect;\n  }\n\n  async expectChoiceCount(count: number): Promise<void> {\n    await expect(this.selectableChoices).toHaveCount(count);\n  }\n\n  getChoiceWithText(text: string): Locator {\n    return this.selectableChoices.filter({ hasText: text });\n  }\n}\n"
  },
  {
    "path": "test-e2e/test-suit.ts",
    "content": "import { expect, type Locator, type Page } from '@playwright/test';\nimport { lock } from 'cross-process-lock';\nimport { writeFileSync, existsSync } from 'fs';\n\nexport class TestSuit {\n  readonly testId: string;\n\n  readonly url: string;\n\n  readonly page: Page;\n\n  readonly group: Locator;\n\n  readonly input: Locator;\n\n  readonly wrapper: Locator;\n\n  readonly itemList: Locator;\n\n  readonly items: Locator;\n\n  readonly dropdown: Locator;\n\n  readonly choicesBundle: string | undefined;\n\n  constructor(page: Page, choicesBundle: string | undefined, url: string, testId: string) {\n    this.choicesBundle = choicesBundle;\n    this.testId = testId;\n    this.url = url;\n    this.page = page;\n    this.group = page.getByTestId(this.testId);\n    this.input = this.group.locator('input[type=\"search\"]');\n    this.wrapper = this.group.locator('.choices').first();\n    this.itemList = this.group.locator('.choices__list.choices__list--multiple, .choices__list.choices__list--single');\n    this.items = this.itemList.locator('.choices__item:not(.choices__placeholder)');\n    this.dropdown = this.group.locator('.choices__list.choices__list--dropdown');\n  }\n\n  logConsole(): void {\n    this.page.on('console', (msg) => {\n      // eslint-disable-next-line no-console\n      console.log(msg);\n    });\n  }\n\n  async start(textInput?: string): Promise<void> {\n    if (this.choicesBundle) {\n      await this.page.route('/assets/scripts/choices.js', (route) => route.continue({ url: this.choicesBundle }));\n      await this.page.route('/assets/scripts/choices.min.js', (route) => route.continue({ url: this.choicesBundle }));\n    }\n\n    // reduce external network traffic\n    await this.page.route('**polyfill**', (route) => route.abort('blockedbyresponse'));\n    // disable google analytics, as it can weirdly fail sometimes\n    await this.page.route('https://www.google-analytics.com/analytics.js', (route) => route.abort('blockedbyresponse'));\n    await this.page.clock.install();\n\n    await this.page.goto(this.url);\n\n    await this.group.scrollIntoViewIfNeeded();\n\n    if (textInput) {\n      await this.typeTextAndEnter(textInput);\n    } else {\n      await this.wrapper.focus();\n      await this.advanceClock();\n    }\n  }\n\n  async advanceClock(): Promise<void> {\n    // dropdown uses requestAnimationFrame for show/hide\n    await this.page.clock.runFor(1000);\n  }\n\n  async selectByKeyPress(textInput: string): Promise<void> {\n    await this.wrapper.focus();\n    await this.advanceClock();\n    await this.input.pressSequentially(textInput);\n    await this.advanceClock();\n    await this.expectVisibleDropdown();\n  }\n\n  async selectByClick(): Promise<void> {\n    await this.wrapper.click();\n    await this.advanceClock();\n    await this.expectVisibleDropdown();\n  }\n\n  async typeTextAndEnter(textInput: string): Promise<void> {\n    await this.typeText(textInput);\n    await this.enterKey();\n  }\n\n  async typeText(textInput: string): Promise<void> {\n    await this.input.focus();\n    await this.advanceClock();\n\n    await this.input.fill(textInput);\n    await this.advanceClock();\n  }\n\n  async keyPress(key: string, _locator?: Locator): Promise<void> {\n    const locator = _locator || this.input;\n    await locator.focus();\n    await this.advanceClock();\n    await locator.press(key);\n    await this.advanceClock();\n  }\n\n  ctrlA(locator?: Locator): Promise<void> {\n    return this.keyPress('ControlOrMeta+KeyA', locator);\n  }\n\n  ctrlX(locator?: Locator): Promise<void> {\n    return this.keyPress('ControlOrMeta+KeyX', locator);\n  }\n\n  ctrlC(locator?: Locator): Promise<void> {\n    return this.keyPress('ControlOrMeta+KeyC', locator);\n  }\n\n  ctrlV(locator?: Locator): Promise<void> {\n    return this.keyPress('ControlOrMeta+KeyV', locator);\n  }\n\n  enterKey(locator?: Locator): Promise<void> {\n    return this.keyPress('Enter', locator);\n  }\n\n  escapeKey(locator?: Locator): Promise<void> {\n    return this.keyPress('Escape', locator);\n  }\n\n  backspaceKey(locator?: Locator): Promise<void> {\n    return this.keyPress('Backspace', locator);\n  }\n\n  async expectVisibleDropdown(): Promise<void> {\n    await this.advanceClock();\n\n    await this.dropdown.waitFor({ state: 'visible' });\n    await expect(this.dropdown).toBeVisible();\n  }\n\n  async expectVisibleDropdownWithItem(text: string): Promise<void> {\n    await this.advanceClock();\n\n    await expect(this.dropdown.filter({ hasText: text })).toHaveCount(1);\n    await this.expectVisibleDropdown();\n  }\n\n  async expectVisibleNoticeHtml(html: string, singleItem: boolean = false): Promise<void> {\n    await this.advanceClock();\n\n    if (singleItem) {\n      await expect(this.dropdown.locator('> *:not(input)')).toHaveCount(1);\n    }\n    expect(await this.dropdown.locator('.choices__notice').innerHTML()).toEqual(html);\n    await this.expectVisibleDropdown();\n  }\n\n  async expectHiddenDropdown(): Promise<void> {\n    await this.advanceClock();\n    await this.dropdown.waitFor({ state: 'hidden' });\n    await expect(this.dropdown).toBeHidden();\n  }\n\n  async expectHiddenNotice(singleItem: boolean = false): Promise<void> {\n    await this.advanceClock();\n\n    if (singleItem) {\n      await expect(this.dropdown.locator('> *:not(input)')).toHaveCount(0);\n    }\n    await expect(this.dropdown.locator('.choices__notice')).toBeHidden();\n  }\n\n  // eslint-disable-next-line class-methods-use-this\n  getWrappedElement(): Locator {\n    throw new Error('Not implemented');\n  }\n\n  getWrapper(): Locator {\n    return this.wrapper;\n  }\n\n  async expectedValue(text: string): Promise<void> {\n    if (text !== '') {\n      await expect(this.items.filter({ hasText: text })).not.toHaveCount(0);\n    }\n\n    expect(await this.getWrappedElement().inputValue()).toEqual(text);\n  }\n\n  async expectedItemCount(count: number): Promise<void> {\n    await expect(this.items).toHaveCount(count);\n  }\n\n  // eslint-disable-next-line class-methods-use-this\n  async crossProcessLock(func: () => Promise<void>): Promise<void> {\n    // playwright lacks clipboard isolation, so use a lock to ensure other tests don't modify the clipboard at the same time\n    // https://github.com/microsoft/playwright/issues/13097#issuecomment-1445271511\n    const name = 'test-results/clipboard';\n    if (!existsSync(name)) {\n      writeFileSync(name, '', 'utf8');\n    }\n    const unlock = await lock(name, { waitTimeout: 30000 });\n    try {\n      await func();\n    } finally {\n      await unlock();\n    }\n  }\n\n  async pasteText(text: string, _locator?: Locator): Promise<void> {\n    const locator = _locator || this.input;\n\n    await this.page.evaluate(() => {\n      if (!document.querySelector('textarea#pasteTarget')) {\n        document.body.insertAdjacentHTML('afterbegin', \"<textarea id='pasteTarget'></textarea>\");\n      }\n    });\n\n    const target = this.page.locator('textarea#pasteTarget');\n    await target.fill(''); // empty any value\n    await target.fill(text);\n\n    await this.crossProcessLock(async () => {\n      await target.selectText(); // Focus & Ctrl+a\n      await this.ctrlC(target);\n\n      await this.selectByClick();\n\n      await this.ctrlV(locator);\n    });\n\n    await this.advanceClock();\n    await expect(locator).toHaveValue(text);\n  }\n}\n"
  },
  {
    "path": "test-e2e/tests/demo-page.spec.ts",
    "content": "import { expect } from '@playwright/test';\nimport { test } from '../bundle-test';\nimport { SelectTestSuit } from '../select-test-suit';\nimport { DEFAULT_CLASSNAMES } from '../../src';\n// import { mkdirSync } from 'fs';\n// import path from 'path';\n\nconst { describe } = test;\n// describe.configure({ mode: 'serial', retries: 0 });\n\ndescribe(`Choices`, () => {\n  const testUrl = '/index.html';\n  describe(`slow`, () => {\n    test.setTimeout(30000);\n    const testId = 'custom-templates';\n\n    test('screenshot', async ({ page, bundle }) => {\n      const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n\n      await page.routeFromHAR('./test-e2e/hars/discogs.har', {\n        url: 'https://api.discogs.com/**',\n        update: false, // https://playwright.dev/docs/mock#replaying-from-har\n      });\n\n      await suite.startWithClick();\n      await suite.expectVisibleDropdown();\n      await suite.input.press('ArrowDown');\n      await suite.advanceClock();\n\n      await expect(page).toHaveScreenshot({\n        fullPage: true,\n        maxDiffPixels: 200,\n        timeout: 30000,\n      });\n    });\n  });\n\n  describe(`functionality`, () => {\n    test('reset form', async ({ page, bundle }) => {\n      const testId = 'reset-simple';\n      const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n      await suite.startWithClick();\n\n      await suite.expectedItemCount(1);\n      await expect(suite.items.first()).toHaveText('Option 2');\n\n      await suite.selectableChoices.first().click();\n      await suite.expectedItemCount(1);\n      await expect(suite.items.first()).toHaveText('Option 1');\n\n      await page.getByTestId('reset-form').getByRole('button', { name: /reset/i }).click();\n\n      await suite.expectedItemCount(1);\n      await expect(suite.items.first()).toHaveText('Option 2');\n    });\n\n    test('show invalid on required form submit', async ({ page, bundle }) => {\n      const testId = 'invalid-select';\n      const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n      await suite.startWithClick();\n\n      await page\n        .getByTestId('invalid-form')\n        .getByRole('button', { name: /submit/i })\n        .click();\n\n      await suite.advanceClock();\n\n      await expect(suite.getWrapper()).toHaveClass(\n        `${DEFAULT_CLASSNAMES.containerOuter} ${DEFAULT_CLASSNAMES.invalidState}`,\n      );\n    });\n  });\n});\n"
  },
  {
    "path": "test-e2e/tests/select-multiple-performance.spec.ts",
    "content": "import { expect } from '@playwright/test';\nimport { test } from '../bundle-test';\nimport { SelectTestSuit } from '../select-test-suit';\n\nconst { describe } = test;\n\nconst testUrl = '/test/select-multiple/index-performance.html';\n\ndescribe(`Choices - select multiple (performance tests)`, () => {\n  // test.setTimeout(30000);\n\n  describe('scenarios', () => {\n    describe('basic', () => {\n      const testId = 'basic';\n      const inputValue = 'test';\n\n      describe('focusing on container', () => {\n        describe('pressing enter key', () => {\n          test('toggles the dropdown', async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.start();\n            await suite.wrapper.focus();\n            await suite.enterKey();\n            await suite.expectVisibleDropdown();\n            await suite.escapeKey();\n            await suite.expectHiddenDropdown();\n          });\n        });\n\n        describe('pressing an alpha-numeric key', () => {\n          test('opens the dropdown and the input value', async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.start();\n            await suite.selectByKeyPress(inputValue);\n            await expect(suite.input).toHaveValue(inputValue);\n          });\n        });\n      });\n\n      describe('selecting choices', () => {\n        const selectedChoiceText = 'Choice 1$';\n\n        test('allows selecting choices from dropdown', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n\n          await suite.choices.first().click();\n          await expect(suite.items.last()).toHaveText(selectedChoiceText);\n        });\n\n        test('remove selected choice from dropdown list', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n\n          await suite.choices.first().click();\n          await expect(suite.choices.first()).not.toHaveText(selectedChoiceText);\n          await expect(suite.items.last()).toHaveText(selectedChoiceText);\n        });\n\n        test('multiple choices', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n\n          await suite.expectedItemCount(1000);\n          await suite.expectChoiceCount(1000);\n          await suite.expectVisibleDropdown();\n\n          await suite.getChoiceWithText('Choice 1$').click();\n          await suite.expectedItemCount(1001);\n          await suite.expectChoiceCount(999);\n          await suite.expectVisibleDropdown();\n\n          await suite.getChoiceWithText('Choice 3$').click();\n          await suite.expectedItemCount(1002);\n          await suite.expectChoiceCount(998);\n          await suite.expectVisibleDropdown();\n        });\n\n        /* This test is unreasonably slow due to selecting over a thousand items...\n        describe('slowly', () => {\n          test.setTimeout(60000);\n          test('all available choices', async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.startWithClick();\n\n            const itemCount = await suite.items.count();\n            const count = await suite.choices.count();\n\n            for (let i = 1; i < count + 1; i++) {\n              await suite.expectVisibleDropdown();\n              await suite.getChoiceWithText(`Choice ${i * 2 - 1}$`).click();\n              await suite.advanceClock();\n              await suite.expectedItemCount(itemCount + i);\n              await expect(suite.selectableChoices).toHaveCount(count - i);\n            }\n\n            await suite.expectVisibleNoticeHtml('No choices to choose from', true)\n          });\n        });\n        */\n      });\n\n      describe('keys for choice', () => {\n        test('up/down arrows for selection', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n\n          await suite.input.press('ArrowDown');\n          await expect(suite.choices.first()).not.toHaveClass(/is-highlighted/);\n          await expect(suite.choices.nth(1)).toHaveClass(/is-highlighted/);\n\n          await suite.input.press('ArrowUp');\n          await expect(suite.choices.first()).toHaveClass(/is-highlighted/);\n          await expect(suite.choices.nth(1)).not.toHaveClass(/is-highlighted/);\n        });\n\n        test('page-up/page-down arrows for selection', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n\n          await suite.input.press('PageDown');\n          await expect(suite.choices.first()).not.toHaveClass(/is-highlighted/);\n          await expect(suite.choices.last()).toHaveClass(/is-highlighted/);\n\n          await suite.input.press('PageUp');\n          await expect(suite.choices.first()).toHaveClass(/is-highlighted/);\n          await expect(suite.choices.last()).not.toHaveClass(/is-highlighted/);\n        });\n      });\n\n      describe('searching choices', () => {\n        describe('on input', () => {\n          describe('searching by label', () => {\n            test('displays choices filtered by inputted value', async ({ page, bundle }) => {\n              const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n              await suite.startWithClick();\n              await suite.typeText('item2');\n\n              await suite.expectVisibleDropdownWithItem('Choice 2');\n            });\n          });\n\n          describe('searching by value', () => {\n            test('displays choices filtered by inputted value - by character', async ({ page, bundle }) => {\n              const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n              const searchTerm = 'Choice 3';\n              await suite.startWithClick();\n              for (const t of [...searchTerm]) {\n                await suite.typeText(t);\n              }\n              // await suite.typeText(searchTerm);\n\n              await suite.expectVisibleDropdownWithItem(searchTerm);\n            });\n\n            test('displays choices filtered by inputted value - by phrase', async ({ page, bundle }) => {\n              const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n              const searchTerm = 'Choice 3';\n              await suite.startWithClick();\n              await suite.typeText(searchTerm);\n\n              await suite.expectVisibleDropdownWithItem(searchTerm);\n            });\n          });\n\n          describe('no results found', () => {\n            test('displays \"no results found\" prompt', async ({ page, bundle }) => {\n              const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n              await suite.startWithClick();\n              await suite.typeText('faergge');\n\n              await suite.expectVisibleNoticeHtml('No results found', true);\n            });\n          });\n        });\n      });\n\n      describe('disabling', () => {\n        describe('on disable', () => {\n          test('disables the search input', async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.startWithClick();\n            await suite.group.locator('button.disable').click();\n            await expect(suite.wrapper).toBeDisabled();\n            await expect(suite.input).toBeDisabled();\n          });\n        });\n      });\n\n      describe('enabling', () => {\n        describe('on enable', () => {\n          test('enables the search input', async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.startWithClick();\n            await suite.group.locator('button.disable').click();\n            await suite.group.locator('button.enable').click();\n            await expect(suite.wrapper).toBeEnabled();\n            await expect(suite.input).toBeEnabled();\n          });\n        });\n      });\n\n      describe('setting options', () => {\n        test.setTimeout(30000);\n        test('setChoices', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n          await suite.group.locator('button.setChoices').click();\n        });\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test-e2e/tests/select-multiple.spec.ts",
    "content": "import { expect } from '@playwright/test';\nimport { test } from '../bundle-test';\nimport { SelectTestSuit } from '../select-test-suit';\nimport { sanitise } from '../../src/scripts/lib/utils';\n\nconst { describe } = test;\n// describe.configure({ mode: 'serial', retries: 0 });\n\nconst testUrl = '/test/select-multiple/index.html';\ndescribe(`Choices - select multiple`, () => {\n  describe('scenarios', () => {\n    describe('basic', () => {\n      const testId = 'basic';\n      const inputValue = 'test';\n\n      describe('focusing on container', () => {\n        describe('pressing enter key', () => {\n          test('toggles the dropdown', async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.start();\n            await suite.wrapper.focus();\n            await suite.enterKey();\n            await suite.expectVisibleDropdown();\n            await suite.escapeKey();\n            await suite.expectHiddenDropdown();\n          });\n        });\n\n        describe('pressing an alpha-numeric key', () => {\n          test('opens the dropdown and the input value', async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.start();\n            await suite.selectByKeyPress(inputValue);\n            await expect(suite.input).toHaveValue(inputValue);\n          });\n        });\n      });\n\n      describe('selecting choices', () => {\n        const selectedChoiceText = 'Choice 1';\n\n        test('allows selecting choices from dropdown', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n\n          await suite.choices.first().click();\n          await expect(suite.items.last()).toHaveText(selectedChoiceText);\n          await expect(suite.items.last()).not.toHaveText('!--');\n        });\n\n        test('remove selected choice from dropdown list', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n\n          await suite.choices.first().click();\n          await expect(suite.choices.first()).not.toHaveText(selectedChoiceText);\n          await expect(suite.items.last()).toHaveText(selectedChoiceText);\n        });\n\n        test('multiple choices', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n\n          await suite.expectedItemCount(0);\n          await suite.expectChoiceCount(4);\n          await suite.expectVisibleDropdown();\n\n          await suite.getChoiceWithText('Choice 1').click();\n          await suite.expectedItemCount(1);\n          await suite.expectChoiceCount(3);\n          await suite.expectVisibleDropdown();\n\n          await suite.getChoiceWithText('Choice 2').click();\n          await suite.expectedItemCount(2);\n          await suite.expectChoiceCount(2);\n          await suite.expectVisibleDropdown();\n        });\n\n        test('all available choices', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n\n          const count = await suite.choices.count();\n\n          for (let i = 1; i < count + 1; i++) {\n            await suite.expectVisibleDropdown();\n            await suite.getChoiceWithText(`Choice ${i}`).click();\n            await suite.advanceClock();\n            await suite.expectedItemCount(i);\n            await expect(suite.selectableChoices).toHaveCount(count - i);\n          }\n\n          await suite.expectVisibleNoticeHtml('No choices to choose from', true);\n        });\n      });\n\n      describe('keys for choice', () => {\n        test('up/down arrows for selection', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n\n          await suite.input.press('ArrowDown');\n          await expect(suite.choices.first()).not.toHaveClass(/is-highlighted/);\n          await expect(suite.choices.nth(1)).toHaveClass(/is-highlighted/);\n\n          await suite.input.press('ArrowUp');\n          await expect(suite.choices.first()).toHaveClass(/is-highlighted/);\n          await expect(suite.choices.nth(1)).not.toHaveClass(/is-highlighted/);\n        });\n\n        test('page-up/page-down arrows for selection', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n\n          await suite.input.press('PageDown');\n          await expect(suite.choices.first()).not.toHaveClass(/is-highlighted/);\n          await expect(suite.choices.last()).toHaveClass(/is-highlighted/);\n\n          await suite.input.press('PageUp');\n          await expect(suite.choices.first()).toHaveClass(/is-highlighted/);\n          await expect(suite.choices.last()).not.toHaveClass(/is-highlighted/);\n        });\n      });\n\n      describe('on cmd+a', () => {\n        test('highlights selected items', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n          await suite.selectableChoices.first().click();\n          await suite.ctrlA();\n          await suite.expectVisibleDropdown();\n\n          expect(await suite.itemList.locator('.is-highlighted').count()).toEqual(1);\n        });\n\n        describe('on backspace', () => {\n          test('clears selected inputted values', async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.startWithClick();\n            await suite.selectableChoices.first().click();\n            await suite.ctrlA();\n            await suite.backspaceKey();\n            await suite.expectVisibleDropdown();\n\n            expect(await suite.itemList.locator('.is-highlighted').count()).toEqual(0);\n          });\n        });\n      });\n\n      describe('searching choices', () => {\n        const validValue = 'item2';\n        const validLabelForValue = 'Choice 2';\n        const validLabel = 'Choice 3';\n        const invalidLabel = 'faergge';\n\n        describe('on input', () => {\n          describe('searching by label', () => {\n            test('displays choices filtered by inputted value', async ({ page, bundle }) => {\n              const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n              await suite.startWithClick();\n              await suite.typeText(validValue);\n\n              await suite.expectVisibleDropdownWithItem(validLabelForValue);\n            });\n          });\n\n          describe('searching by value', () => {\n            test('displays choices filtered by inputted value', async ({ page, bundle }) => {\n              const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n              await suite.startWithClick();\n              await suite.typeText(validLabel);\n\n              await suite.expectVisibleDropdownWithItem(validLabel);\n            });\n          });\n\n          describe('no results found', () => {\n            test('displays \"no results found\" prompt', async ({ page, bundle }) => {\n              const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n              await suite.startWithClick();\n              await suite.typeText(invalidLabel);\n\n              await suite.expectVisibleNoticeHtml('No results found', true);\n            });\n          });\n        });\n        describe('on paste', () => {\n          // playwright lacks clipboard isolation, so use serial mode to try to work around it.\n          // https://github.com/microsoft/playwright/issues/13097\n          describe.configure({ mode: 'serial', timeout: 2000 });\n\n          describe('searching by label', () => {\n            test('displays choices filtered by inputted value', async ({ page, bundle }) => {\n              const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n              await suite.startWithClick();\n\n              await suite.pasteText(validValue);\n\n              await suite.expectVisibleDropdownWithItem(validLabelForValue);\n            });\n          });\n\n          describe('searching by value', () => {\n            test('displays choices filtered by inputted value', async ({ page, bundle }) => {\n              const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n              await suite.startWithClick();\n\n              await suite.pasteText(validLabel);\n\n              await suite.expectVisibleDropdownWithItem(validLabel);\n            });\n          });\n\n          describe('no results found', () => {\n            test('displays \"no results found\" prompt', async ({ page, bundle }) => {\n              const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n              await suite.startWithClick();\n\n              await suite.pasteText(invalidLabel);\n\n              await suite.expectVisibleNoticeHtml('No results found', true);\n            });\n          });\n        });\n      });\n\n      describe('disabling', () => {\n        describe('on disable', () => {\n          test('disables the search input', async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.startWithClick();\n            await suite.group.locator('button.disable').click();\n            await expect(suite.wrapper).toBeDisabled();\n            await expect(suite.input).toBeDisabled();\n          });\n        });\n      });\n\n      describe('enabling', () => {\n        describe('on enable', () => {\n          test('enables the search input', async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.startWithClick();\n            await suite.group.locator('button.disable').click();\n            await suite.group.locator('button.enable').click();\n            await expect(suite.wrapper).toBeEnabled();\n            await expect(suite.input).toBeEnabled();\n          });\n        });\n      });\n    });\n\n    describe('aria attributes', () => {\n      const testId = 'disabled-choice';\n      test('aria-selected', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n\n        await suite.input.press('ArrowDown');\n        await expect(suite.choices.first()).toHaveAttribute('aria-selected', 'false');\n        await expect(suite.choices.nth(1)).toHaveAttribute('aria-selected', 'true');\n        await expect(suite.choices.nth(2)).toHaveAttribute('aria-selected', 'false');\n        await expect(suite.choices.nth(3)).not.toHaveAttribute('aria-selected');\n\n        await suite.input.press('ArrowUp');\n        await expect(suite.choices.first()).toHaveAttribute('aria-selected', 'true');\n        await expect(suite.choices.nth(1)).toHaveAttribute('aria-selected', 'false');\n        await expect(suite.choices.nth(2)).toHaveAttribute('aria-selected', 'false');\n        await expect(suite.choices.nth(3)).not.toHaveAttribute('aria-selected');\n      });\n    });\n\n    describe('render selected choices', () => {\n      const testId = 'render-selected-choices';\n      describe('selecting choices', () => {\n        const selectedChoiceText = 'Choice 1';\n\n        test('not removing selected choice from dropdown list', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n\n          await expect(suite.choices.first()).toHaveText(selectedChoiceText);\n          await expect(suite.choices.first()).toHaveClass(/is-selected/);\n          await expect(suite.items.last()).toHaveText(selectedChoiceText);\n        });\n\n        test('multiple choices', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n\n          await expect(suite.getChoiceWithText(selectedChoiceText)).toHaveClass(/is-selected/);\n          await suite.expectedItemCount(1);\n          await suite.expectChoiceCount(4);\n          await suite.expectVisibleDropdown();\n\n          await suite.getChoiceWithText('Choice 2').click();\n          await expect(suite.getChoiceWithText('Choice 2')).toHaveClass(/is-selected/);\n          await suite.expectedItemCount(2);\n          await suite.expectChoiceCount(4);\n          await suite.expectVisibleDropdown();\n        });\n\n        test('all available choices', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n\n          const count = await suite.choices.count();\n\n          for (let i = 1; i < count + 1; i++) {\n            await suite.expectVisibleDropdown();\n            await suite.getChoiceWithText(`Choice ${i}`).click();\n            await suite.advanceClock();\n            await suite.expectedItemCount(i);\n            if (i < count) {\n              await expect(suite.getChoiceWithText(`Choice ${i}`)).toHaveClass(/is-selected/);\n              await expect(suite.selectableChoices).toHaveCount(count);\n            } else {\n              await suite.expectHiddenNotice();\n            }\n          }\n        });\n      });\n\n      describe('keys for choice', () => {\n        test('up/down arrows for selection', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n\n          await suite.input.press('ArrowDown');\n          await expect(suite.choices.first()).not.toHaveClass(/is-highlighted/);\n          await expect(suite.choices.nth(1)).toHaveClass(/is-highlighted/);\n\n          await suite.input.press('ArrowUp');\n          await expect(suite.choices.first()).toHaveClass(/is-highlighted/);\n          await expect(suite.choices.nth(1)).not.toHaveClass(/is-highlighted/);\n        });\n\n        test('page-up/page-down arrows for selection', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n\n          await suite.input.press('PageDown');\n          await expect(suite.choices.first()).not.toHaveClass(/is-highlighted/);\n          await expect(suite.choices.last()).toHaveClass(/is-highlighted/);\n\n          await suite.input.press('PageUp');\n          await expect(suite.choices.first()).toHaveClass(/is-highlighted/);\n          await expect(suite.choices.last()).not.toHaveClass(/is-highlighted/);\n        });\n      });\n    });\n\n    describe('selected choices highlighted in dropdown', () => {\n      const selectedChoice = 'Choice 3';\n      test('on', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, 'selected-choice-in-dropdown');\n        await suite.startWithClick();\n\n        await suite.expectedItemCount(2);\n        await suite.expectedValue(selectedChoice);\n\n        await expect(suite.choices.nth(2)).toHaveClass(/is-highlighted/);\n        /* known limitation due to highlighting the first choice only right now */\n        // await expect(suite.choices.nth(3)).toHaveClass(/is-highlighted/);\n      });\n    });\n\n    describe('remove button', () => {\n      const testId = 'remove-button';\n      describe('on click', () => {\n        test('removes default', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n          await suite.expectVisibleDropdown();\n\n          await suite.expectedItemCount(1);\n          await suite.expectedValue('Choice 1');\n\n          await suite.items.getByRole('button', { name: 'Remove item' }).last().click();\n          await suite.advanceClock();\n\n          await suite.expectedItemCount(0);\n          await suite.expectedValue('');\n          await suite.escapeKey();\n          await suite.expectHiddenDropdown();\n        });\n\n        test('removes selected choice', async ({ page, bundle }) => {\n          const defaultChoice = 'Choice 1';\n          const selectedChoice = 'Choice 4';\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n\n          await suite.expectedItemCount(1);\n          await suite.expectedValue(defaultChoice);\n\n          const choice = suite.choices.last();\n          await expect(choice).toHaveText(selectedChoice);\n          await choice.click();\n\n          await suite.expectedItemCount(2);\n\n          await suite.items.getByRole('button', { name: 'Remove item' }).last().click();\n          await suite.advanceClock();\n\n          await suite.expectedItemCount(1);\n          await suite.expectedValue('Choice 1');\n          await suite.escapeKey();\n          await suite.expectHiddenDropdown();\n        });\n      });\n    });\n\n    describe('duplicate-items', () => {\n      test('shows all duplicate items', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, 'duplicate-items-allowed');\n        await suite.startWithClick();\n\n        await expect(suite.selectableChoices).toHaveCount(5);\n      });\n      test('shows unique items', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, 'duplicate-items-disallowed');\n        await suite.startWithClick();\n\n        await expect(suite.selectableChoices).toHaveCount(3);\n      });\n    });\n\n    describe('Selected choices rendering', () => {\n      test('Render selected choices', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, 'renderSelectedChoices-true');\n        await suite.startWithClick();\n\n        await expect(suite.selectableChoices).toHaveCount(1);\n      });\n    });\n\n    describe('no choices', () => {\n      const testId = 'no-choices';\n      test('shows no choices banner', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n\n        await expect(suite.selectableChoices).toHaveCount(0);\n        await suite.expectVisibleNoticeHtml('No choices to choose from', true);\n      });\n    });\n\n    describe('No choices (besides selected)', () => {\n      const testId = 'no-choices2';\n      test('shows no choices banner', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n\n        await expect(suite.selectableChoices).toHaveCount(0);\n        await suite.expectVisibleNoticeHtml('No choices to choose from', true);\n      });\n\n      test('shows no results banner and then no choices banner', async ({ page, bundle }) => {\n        const invalidLabel = 'faergge';\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n\n        await suite.typeText(invalidLabel);\n        await expect(suite.selectableChoices).toHaveCount(0);\n        await suite.expectVisibleNoticeHtml('No results found', true);\n\n        await suite.typeText('');\n        await expect(suite.selectableChoices).toHaveCount(0);\n        await suite.expectVisibleNoticeHtml('No choices to choose from', true);\n      });\n    });\n\n    describe('disabled choice', () => {\n      const testId = 'disabled-choice';\n      const firstChoice = 'Choice 1';\n      test('does not change selected choice', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n        await suite.selectableChoices.first().click();\n\n        await suite.expectedItemCount(1);\n        await suite.expectedValue(firstChoice);\n\n        const choice = suite.choices.last();\n        await expect(choice).toBeDisabled();\n        await choice.click({ force: true });\n\n        await suite.expectedItemCount(1);\n        await suite.expectedValue(firstChoice);\n      });\n    });\n\n    describe('Disabled first choice by options', () => {\n      const testId = 'disabled-first-choice-via-options';\n      const firstChoice = 'Choice 2';\n      test('does not change selected choice', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n        await suite.getChoiceWithText(firstChoice).click();\n        await suite.advanceClock();\n\n        await suite.expectedItemCount(1);\n        await suite.expectedValue(firstChoice);\n\n        const choice = suite.choices.first();\n        await expect(choice).toBeDisabled();\n        await choice.click({ force: true });\n\n        await suite.expectedItemCount(1);\n        await suite.expectedValue(firstChoice);\n      });\n    });\n\n    describe('disabled via attribute', () => {\n      const testId = 'disabled-via-attr';\n      test('disables the search input', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.start();\n        await suite.wrapper.click({ force: true });\n\n        await expect(suite.wrapper).toBeDisabled();\n        await suite.expectHiddenDropdown();\n      });\n    });\n\n    describe('disabled via fieldset', () => {\n      const testId = 'disabled-via-fieldset';\n      test('disables the search input', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.start();\n        await suite.wrapper.click({ force: true });\n\n        await expect(suite.wrapper).toBeDisabled();\n        await suite.expectHiddenDropdown();\n      });\n    });\n\n    describe('selection limit', () => {\n      const displaysTestId = 'selection-limit';\n      const selectionLimit = 5;\n\n      test('displays \"limit reached\" prompt', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, displaysTestId);\n        await suite.startWithClick();\n\n        for (let index = 0; index < selectionLimit; index++) {\n          await suite.selectableChoices.first().click();\n          await suite.advanceClock();\n        }\n\n        await suite.expectVisibleNoticeHtml(`Only ${selectionLimit} values can be added`);\n      });\n\n      const hidesTestId = 'selection-limit-note-after-unselecting-choice';\n      test('hides \"limit reached\" prompt', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, hidesTestId);\n        await suite.startWithClick();\n\n        for (let index = 0; index < selectionLimit; index++) {\n          await suite.selectableChoices.first().click();\n          await suite.advanceClock();\n        }\n\n        await suite.expectVisibleNoticeHtml(`Only ${selectionLimit} values can be added`);\n\n        await suite.items.getByRole('button', { name: 'Remove item' }).last().click();\n        await suite.advanceClock();\n\n        await suite.expectHiddenNotice();\n      });\n    });\n\n    describe('prepend/append', () => {\n      const testId = 'prepend-append';\n      const textInput = 'Choice 1';\n      test('prepends and appends value to inputted value', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n        await suite.getChoiceWithText(textInput).click();\n\n        const item = suite.items.first();\n        await expect(item).toHaveText(textInput);\n        await expect(item).toHaveAttribute('data-value', `before-${textInput}-after`);\n      });\n    });\n\n    describe('render choice limit', () => {\n      const testId = 'render-choice-limit';\n      test('only displays given number of choices in the dropdown', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n\n        expect(await suite.choices.count()).toEqual(1);\n      });\n    });\n\n    describe('search disabled', () => {\n      const testId = 'search-disabled';\n      test('does not display a search input', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n\n        await expect(suite.input).toHaveCount(0);\n      });\n\n      test('allows selecting choices from dropdown', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n\n        const choice = suite.choices.last();\n        const text = await choice.innerText();\n        await expect(choice).toBeEnabled();\n        await choice.click();\n\n        await suite.expectedItemCount(1);\n        await suite.expectedValue(text);\n        await suite.expectVisibleDropdown();\n      });\n    });\n\n    describe('search floor', () => {\n      const testId = 'search-floor';\n      describe('on input', () => {\n        describe('search floor not reached', () => {\n          test('displays choices not filtered by inputted value', async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.startWithClick();\n\n            const searchTerm = 'item 2';\n            await suite.typeText(searchTerm);\n            await suite.expectVisibleDropdown();\n            await expect(suite.choices.first()).not.toHaveText(searchTerm);\n          });\n        });\n\n        describe('search floor reached', () => {\n          test('displays choices filtered by inputted value', async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.startWithClick();\n\n            const searchTerm = 'Choice 2';\n\n            await suite.typeText(searchTerm);\n            await suite.expectVisibleDropdown();\n            await expect(suite.choices.first()).toHaveText(searchTerm);\n          });\n        });\n      });\n    });\n\n    describe('search hide selected', () => {\n      const testId = 'search-hide-selected';\n\n      describe('selecting choices and searching', () => {\n        test('selected choices do not appear in search results', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n\n          await suite.getChoiceWithText('Choice 1').click();\n          await suite.expectedItemCount(1);\n\n          await suite.typeText('Choice');\n          await suite.expectVisibleDropdown();\n\n          await expect(suite.choices.filter({ hasText: 'Choice 1' })).toHaveCount(0);\n\n          await expect(suite.choices.filter({ hasText: 'Choice 2' })).toHaveCount(1);\n          await expect(suite.choices.filter({ hasText: 'Choice 3' })).toHaveCount(1);\n          await expect(suite.choices.filter({ hasText: 'Choice 4' })).toHaveCount(1);\n        });\n\n        test('selecting multiple choices hides all from search', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n\n          await suite.getChoiceWithText('Choice 1').click();\n          await suite.getChoiceWithText('Choice 2').click();\n          await suite.expectedItemCount(2);\n\n          await suite.typeText('Choice');\n          await suite.expectVisibleDropdown();\n\n          await expect(suite.choices.filter({ hasText: 'Choice 1' })).toHaveCount(0);\n          await expect(suite.choices.filter({ hasText: 'Choice 2' })).toHaveCount(0);\n\n          await expect(suite.choices.filter({ hasText: 'Choice 3' })).toHaveCount(1);\n          await expect(suite.choices.filter({ hasText: 'Choice 4' })).toHaveCount(1);\n        });\n      });\n    });\n\n    [\n      {\n        name: 'empty option value',\n        testId: 'placeholder-via-option-value',\n      },\n      {\n        name: 'option attribute',\n        testId: 'placeholder-via-option-attr',\n      },\n      {\n        name: 'data attribute',\n        testId: 'placeholder-via-data-attr',\n      },\n    ].forEach((arg) => {\n      const { testId } = arg;\n      describe(`Placeholder via ${arg.name}`, () => {\n        describe('when no choice has been selected', () => {\n          test('displays a placeholder', async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.start();\n            await suite.expectHiddenDropdown();\n\n            await suite.expectedItemCount(0);\n            await suite.expectedValue('');\n\n            await expect(suite.itemsWithPlaceholder).toHaveCount(0);\n            await expect(suite.input).toHaveAttribute('placeholder', 'I am a placeholder');\n            await expect(suite.choices.filter({ hasText: 'I am a placeholder' })).toHaveCount(0);\n          });\n        });\n\n        describe('when a choice has been selected', () => {\n          test('displays a placeholder', async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.startWithClick();\n            await suite.expectVisibleDropdown();\n\n            const choice = suite.selectableChoices.first();\n            await choice.click();\n\n            await expect(suite.itemsWithPlaceholder).toHaveCount(1);\n            await expect(suite.input).toHaveAttribute('placeholder', 'I am a placeholder');\n            await expect(suite.choices.filter({ hasText: 'I am a placeholder' })).toHaveCount(0);\n          });\n        });\n\n        describe('when choice list is open', () => {\n          test('displays a placeholder', async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.startWithClick();\n            await suite.expectVisibleDropdown();\n\n            await expect(suite.itemsWithPlaceholder).toHaveCount(0);\n            await expect(suite.input).toHaveAttribute('placeholder', 'I am a placeholder');\n            await expect(suite.choices.filter({ hasText: 'I am a placeholder' })).toHaveCount(0);\n          });\n        });\n      });\n    });\n\n    describe('remote data', () => {\n      const testId = 'remote-data';\n      test('checking placeholder values', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n\n        const jsonLoad = page.waitForResponse('**/data.json');\n        const stopJsonWaiting = await suite.delayData();\n        await suite.start();\n\n        await expect(suite.input).toHaveAttribute('placeholder', 'Loading...');\n\n        stopJsonWaiting();\n        await jsonLoad;\n        await suite.selectByClick();\n\n        await expect(suite.input).toHaveAttribute('placeholder', 'I am a placeholder');\n        await expect(suite.selectableChoices).toHaveCount(10);\n      });\n    });\n\n    describe('scrolling dropdown', () => {\n      const testId = 'scrolling-dropdown';\n      test('shows partial choices list', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n\n        await expect(suite.selectableChoices).toHaveCount(15);\n        // @todo determine how to assert items\n        // await expect(suite.selectableChoices.filter({ has: page.locator(':scope:visible') })).toHaveCount(8);\n      });\n    });\n\n    describe('choice groups', () => {\n      describe('just groups', () => {\n        const testId = 'groups';\n        test('displays', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n\n          await expect(suite.dropdown.locator('.choices__group[data-group]')).toHaveCount(2);\n        });\n      });\n\n      describe('groups and choices', () => {\n        const testId = 'mixed-groups';\n        test('displays', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n\n          await expect(suite.dropdown.locator('.choices__group[data-group]')).toHaveCount(1);\n          expect(await suite.dropdown.locator('.choices__item--choice[data-group-id]').count()).toEqual(1);\n          expect(await suite.dropdown.locator('.choices__item--choice:not([data-group-id])').count()).toBeGreaterThan(\n            1,\n          );\n        });\n      });\n    });\n\n    describe('custom properties via config', () => {\n      const testId = 'custom-properties';\n      const cities = [\n        {\n          country: 'Germany',\n          city: 'Berlin',\n        },\n        {\n          country: 'United Kingdom',\n          city: 'London',\n        },\n        {\n          country: 'Portugal',\n          city: 'Lisbon',\n        },\n      ];\n      describe('on input', () => {\n        cities.forEach(({ country, city }) => {\n          test(`filters choices - ${country} = ${city}`, async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.startWithClick();\n            await suite.typeText(country);\n            await suite.expectVisibleDropdown();\n\n            const choice = suite.selectableChoices.first();\n            await expect(choice).toHaveText(city);\n          });\n\n          test(`filters choices - ${city}`, async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.startWithClick();\n            await suite.typeText(city);\n            await suite.expectVisibleDropdown();\n\n            const choice = suite.selectableChoices.first();\n            await expect(choice).toHaveText(city);\n          });\n        });\n      });\n\n      describe('on paste', () => {\n        // playwright lacks clipboard isolation, so use serial mode to try to work around it.\n        // https://github.com/microsoft/playwright/issues/13097\n        describe.configure({ mode: 'serial', timeout: 30000 });\n\n        cities.forEach(({ country, city }) => {\n          test(`filters choices - ${country} = ${city}`, async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.startWithClick();\n\n            await suite.pasteText(country);\n\n            const choice = suite.selectableChoices.first();\n            await expect(choice).toHaveText(city);\n          });\n\n          test(`filters choices - ${city}`, async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.startWithClick();\n\n            await suite.pasteText(city);\n\n            const choice = suite.selectableChoices.first();\n            await expect(choice).toHaveText(city);\n          });\n        });\n      });\n    });\n\n    describe('custom properties via html', () => {\n      const testId = 'custom-properties-html';\n      describe('on input', () => {\n        [\n          {\n            searchText: 'fantastic',\n            label: 'Label Three',\n          },\n          {\n            searchText: 'foo',\n            label: 'Label Four',\n          },\n        ].forEach(({ searchText, label }) => {\n          test(`filters choices - ${searchText} = ${label}`, async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.startWithClick();\n            await suite.typeText(searchText);\n            await suite.expectVisibleDropdown();\n\n            const choice = suite.selectableChoices.first();\n            await expect(choice).toHaveText(label);\n          });\n        });\n      });\n    });\n\n    describe('non-string values', () => {\n      const testId = 'non-string-values';\n      test('displays expected amount of choices in dropdown', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n\n        await expect(suite.selectableChoices).toHaveCount(4);\n      });\n\n      test('allows selecting choices from dropdown', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n\n        const choice = suite.selectableChoices.first();\n        const choiceText = await choice.textContent();\n        expect(choiceText).toBeTruthy();\n        await choice.click();\n\n        await expect(suite.items.first()).toHaveText(choiceText as string);\n      });\n    });\n\n    describe('within form', () => {\n      const testId = 'within-form';\n      describe('selecting choice', () => {\n        describe('on enter key', () => {\n          test('does not submit form', async ({ page, bundle }) => {\n            let submit = false;\n            await page.route(page.url(), (route) => {\n              submit = true;\n\n              return route.abort();\n            });\n\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.startWithClick();\n            await suite.expectVisibleDropdown();\n\n            const choice = suite.choices.first();\n            const text = await choice.innerText();\n            await expect(choice).toBeEnabled();\n            await choice.click();\n            await suite.advanceClock();\n\n            await suite.expectedItemCount(1);\n            await suite.expectedValue(text);\n            expect(submit).toEqual(false);\n            await suite.expectVisibleDropdown();\n          });\n        });\n      });\n    });\n\n    describe('dynamically setting choice by value', () => {\n      const dynamicallySelectedChoiceValue = 'Choice 2';\n      const testId = 'set-choice-by-value';\n      test('selects choice', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n\n        await expect(suite.items).toHaveText(dynamicallySelectedChoiceValue);\n      });\n\n      test('removes choice from dropdown list', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n\n        await expect(suite.getChoiceWithText(dynamicallySelectedChoiceValue)).toHaveCount(0);\n      });\n\n      test('updates the value of the original input', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n\n        await suite.expectedValue(dynamicallySelectedChoiceValue);\n      });\n    });\n\n    describe('searching by label only', () => {\n      const testId = 'search-by-label';\n      test('gets zero results when searching by value', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n        await suite.typeText('item2');\n\n        await suite.expectVisibleNoticeHtml('No results found', true);\n      });\n\n      test('gets a result when searching by label', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n        await suite.typeText('label1');\n        await suite.expectVisibleDropdown();\n        await suite.escapeKey();\n        await suite.expectHiddenDropdown();\n\n        await expect(suite.items.filter({ hasText: 'label1' })).toHaveCount(0);\n      });\n    });\n\n    describe('html allowed', () => {\n      const textInput = 'testing';\n      const htmlInput = `<b>${textInput}</b>`;\n      const escapedInput = sanitise(htmlInput);\n      describe('set to undefined', () => {\n        const testId = 'allowhtml-undefined';\n        test('does not show html', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n          await suite.typeText(htmlInput);\n          await suite.expectVisibleNoticeHtml(`Press Enter to add <b>\"${escapedInput}\"</b>`);\n          await suite.enterKey();\n\n          await expect(suite.items.last()).toHaveText(htmlInput);\n        });\n      });\n\n      describe('set to true', () => {\n        const testId = 'allowhtml-true';\n        test('does not show html as text', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n          await suite.typeText(htmlInput);\n          await suite.expectVisibleNoticeHtml(`Press Enter to add <b>\"${escapedInput}\"</b>`);\n          await suite.enterKey();\n\n          await expect(suite.items.last()).toHaveText(textInput);\n        });\n      });\n\n      describe('set to true - except user input', () => {\n        const testId = 'allowhtml-true-userinput-false';\n        test('does not show html as text', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n          await suite.typeText(htmlInput);\n          await suite.expectVisibleNoticeHtml(`Press Enter to add <b>\"${escapedInput}\"</b>`);\n          await suite.enterKey();\n\n          await expect(suite.items.last()).toHaveText(htmlInput);\n        });\n      });\n\n      describe('set to false', () => {\n        const testId = 'allowhtml-false';\n        test('does not show html as text', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n          await suite.typeText(htmlInput);\n          await suite.expectVisibleNoticeHtml(`Press Enter to add <b>\"${escapedInput}\"</b>`);\n          await suite.enterKey();\n\n          await expect(suite.items.last()).toHaveText(htmlInput);\n        });\n      });\n    });\n\n    describe('re-initialising a choices instance', () => {\n      const testId = 'new-destroy-init';\n      const testvalue = 'Choice 2';\n      test('preserves the choices & items lists', async ({ page, bundle }) => {\n        let suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n        await suite.typeText(testvalue);\n        await suite.expectVisibleDropdown();\n        await suite.enterKey();\n        await suite.expectedItemCount(1);\n        await suite.expectChoiceCount(2);\n\n        await suite.escapeKey();\n        await suite.expectHiddenDropdown();\n\n        await suite.group.locator('.destroy').click({ force: true });\n        await suite.advanceClock();\n\n        await expect(suite.group.locator('select > optgroup > option')).toHaveCount(1);\n        await expect(suite.group.locator('select > option')).toHaveCount(2);\n\n        await suite.group.locator('.init').click({ force: true });\n        await suite.advanceClock();\n\n        suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.expectedItemCount(1);\n        await suite.expectChoiceCount(2);\n        await suite.expectedValue(testvalue);\n      });\n    });\n\n    describe('autocomplete', () => {\n      const testId = 'autocomplete';\n      test('Expected notice results', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n        await suite.typeText('f');\n        await expect(suite.input).toHaveValue('f');\n        await suite.expectVisibleNoticeHtml('No results found');\n        await suite.typeText('fo');\n        await expect(suite.input).toHaveValue('fo');\n        await suite.expectVisibleDropdownWithItem('Found');\n\n        await suite.keyPress('Backspace');\n        await suite.keyPress('Backspace');\n        await suite.expectVisibleNoticeHtml('No choices to choose from');\n      });\n    });\n\n    describe('Clear choices on add item', () => {\n      const testId = 'clear-on-add';\n      test('Expected items', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n        await suite.expectChoiceCount(2);\n\n        await suite.choices.first().click();\n        await suite.advanceClock();\n        await suite.expectHiddenDropdown();\n        await suite.expectedItemCount(1);\n\n        await suite.wrapper.click();\n        await suite.advanceClock();\n        await suite.expectVisibleNoticeHtml('No choices to choose from', false);\n\n        await suite.keyPress('Backspace');\n        await suite.expectedItemCount(0);\n        await suite.expectChoiceCount(1);\n      });\n    });\n\n    describe('setChoices', () => {\n      test('Expected selected to be preserved', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, 'set-choices-preserve');\n        await suite.start();\n        await suite.advanceClock();\n\n        await suite.expectHiddenDropdown();\n        await suite.expectedValue('Choice 2');\n        await suite.expectedItemCount(1);\n        await suite.expectChoiceCount(2);\n      });\n\n      test('Expected selected to be preserved (no duplicates)', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, 'set-choices-preserve-no-dupes');\n        await suite.start();\n\n        await suite.expectHiddenDropdown();\n        await suite.expectedValue('Choice 2');\n        await suite.expectedItemCount(1);\n        await suite.expectChoiceCount(1);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test-e2e/tests/select-one.spec.ts",
    "content": "import { expect } from '@playwright/test';\nimport { test } from '../bundle-test';\nimport { SelectTestSuit } from '../select-test-suit';\nimport { sanitise } from '../../src/scripts/lib/utils';\n\nconst { describe } = test;\n\nconst testUrl = '/test/select-one/index.html';\n\ndescribe(`Choices - select one`, () => {\n  describe('scenarios', () => {\n    describe('basic', () => {\n      const testId = 'basic';\n      const inputValue = 'test';\n\n      describe('focusing on container', () => {\n        describe('pressing enter key', () => {\n          test('toggles the dropdown', async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.start();\n            await suite.wrapper.focus();\n            await suite.enterKey();\n            await suite.expectVisibleDropdown();\n            await suite.escapeKey();\n            await suite.expectHiddenDropdown();\n          });\n        });\n\n        describe('click selected element', () => {\n          test('toggles the dropdown', async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.startWithClick();\n\n            const box = (await suite.itemList.locator('[data-item]').boundingBox())!;\n            await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2);\n            await page.mouse.down();\n            await suite.advanceClock();\n            await suite.expectVisibleDropdown();\n\n            await page.mouse.up();\n            await suite.advanceClock();\n            await suite.expectHiddenDropdown();\n\n            await page.mouse.down();\n            await suite.advanceClock();\n            await suite.expectHiddenDropdown();\n\n            await page.mouse.up();\n            await suite.advanceClock();\n            await suite.expectVisibleDropdown();\n          });\n        });\n\n        describe('pressing an alpha-numeric key', () => {\n          test('opens the dropdown and the input value', async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.start();\n            await suite.selectByKeyPress(inputValue);\n            await expect(suite.input).toHaveValue(inputValue);\n          });\n        });\n      });\n\n      describe('selecting choices', () => {\n        const selectedChoiceText = 'Choice 1';\n\n        test('allows selecting choices from dropdown', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n\n          await suite.choices.first().click();\n          await expect(suite.items.last()).toHaveText(selectedChoiceText);\n          await expect(suite.items.last()).not.toHaveText('!--');\n        });\n\n        test('does not remove selected choice from dropdown list', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n\n          await suite.choices.first().click();\n          await expect(suite.choices.first()).toHaveText(selectedChoiceText);\n          await expect(suite.items.last()).toHaveText(selectedChoiceText);\n        });\n      });\n\n      describe('keys for choice', () => {\n        test('up/down arrows for selection', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n\n          await suite.input.press('ArrowDown');\n          await expect(suite.choices.first()).not.toHaveClass(/is-highlighted/);\n          await expect(suite.choices.nth(1)).toHaveClass(/is-highlighted/);\n\n          await suite.input.press('ArrowUp');\n          await expect(suite.choices.first()).toHaveClass(/is-highlighted/);\n          await expect(suite.choices.nth(1)).not.toHaveClass(/is-highlighted/);\n        });\n\n        test('page-up/page-down arrows for selection', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n\n          await suite.input.press('PageDown');\n          await expect(suite.choices.first()).not.toHaveClass(/is-highlighted/);\n          await expect(suite.choices.last()).toHaveClass(/is-highlighted/);\n\n          await suite.input.press('PageUp');\n          await expect(suite.choices.first()).toHaveClass(/is-highlighted/);\n          await expect(suite.choices.last()).not.toHaveClass(/is-highlighted/);\n        });\n      });\n\n      describe('searching choices', () => {\n        const validValue = 'item2';\n        const validLabelForValue = 'Choice 2';\n        const validLabel = 'Choice 3';\n        const invalidLabel = 'faergge';\n\n        describe('on input', () => {\n          describe('searching by label', () => {\n            test('displays choices filtered by inputted value', async ({ page, bundle }) => {\n              const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n              await suite.startWithClick();\n              await suite.typeText(validValue);\n\n              await suite.expectVisibleDropdownWithItem(validLabelForValue);\n            });\n          });\n\n          describe('searching by value', () => {\n            test('displays choices filtered by inputted value', async ({ page, bundle }) => {\n              const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n              await suite.startWithClick();\n              await suite.typeText(validLabel);\n\n              await suite.expectVisibleDropdownWithItem(validLabel);\n            });\n          });\n\n          describe('no results found', () => {\n            test('displays \"no results found\" prompt', async ({ page, bundle }) => {\n              const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n              await suite.startWithClick();\n              await suite.typeText(invalidLabel);\n\n              await suite.expectVisibleNoticeHtml('No results found', true);\n            });\n          });\n        });\n        describe('on paste', () => {\n          // playwright lacks clipboard isolation, so use serial mode to try to work around it.\n          // https://github.com/microsoft/playwright/issues/13097\n          describe.configure({ mode: 'serial', timeout: 30000 });\n\n          describe('searching by label', () => {\n            test('displays choices filtered by inputted value', async ({ page, bundle }) => {\n              const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n              await suite.startWithClick();\n\n              await suite.pasteText(validValue);\n\n              await suite.expectVisibleDropdownWithItem(validLabelForValue);\n            });\n          });\n\n          describe('searching by value', () => {\n            test('displays choices filtered by inputted value', async ({ page, bundle }) => {\n              const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n              await suite.startWithClick();\n\n              await suite.pasteText(validLabel);\n\n              await suite.expectVisibleDropdownWithItem(validLabel);\n            });\n          });\n\n          describe('no results found', () => {\n            test('displays \"no results found\" prompt', async ({ page, bundle }) => {\n              const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n              await suite.startWithClick();\n\n              await suite.pasteText(invalidLabel);\n\n              await suite.expectVisibleNoticeHtml('No results found', true);\n            });\n          });\n        });\n      });\n\n      describe('disabling', () => {\n        describe('on disable', () => {\n          test('disables the search input', async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.startWithClick();\n            await suite.group.locator('button.disable').click();\n            await expect(suite.wrapper).toBeDisabled();\n            await expect(suite.input).toBeDisabled();\n          });\n        });\n      });\n\n      describe('enabling', () => {\n        describe('on enable', () => {\n          test('enables the search input', async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.startWithClick();\n            await suite.group.locator('button.disable').click();\n            await suite.group.locator('button.enable').click();\n            await expect(suite.wrapper).toBeEnabled();\n            await expect(suite.input).toBeEnabled();\n          });\n        });\n      });\n    });\n\n    describe('selected choice highlighted in dropdown', () => {\n      const selectedChoice = 'Choice 3';\n      test('on', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, 'selected-choice-in-dropdown');\n        await suite.startWithClick();\n\n        await suite.expectedItemCount(1);\n        await suite.expectedValue(selectedChoice);\n\n        await expect(suite.choices.nth(2)).toHaveClass(/is-highlighted/);\n      });\n    });\n\n    describe('remove button', () => {\n      const testId = 'remove-button';\n      describe('on click', () => {\n        test('removes default', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.start();\n          await suite.expectHiddenDropdown();\n\n          await suite.expectedItemCount(1);\n          await suite.expectedValue('Choice 1');\n\n          await suite.items.getByRole('button', { name: 'Remove item' }).last().click();\n          await suite.advanceClock();\n\n          await suite.expectedItemCount(0);\n          await suite.expectedValue('');\n          await suite.expectHiddenDropdown();\n        });\n\n        test('removes selected choice', async ({ page, bundle }) => {\n          const defaultChoice = 'Choice 1';\n          const selectedChoice = 'Choice 4';\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n\n          await suite.expectedItemCount(1);\n          await suite.expectedValue(defaultChoice);\n\n          const choice = suite.choices.last();\n          await expect(choice).toHaveText(selectedChoice);\n          await choice.click();\n\n          await suite.expectedItemCount(1);\n          await suite.expectedValue(selectedChoice);\n\n          await suite.items.getByRole('button', { name: 'Remove item' }).last().click();\n\n          await suite.expectedItemCount(0);\n          await suite.expectedValue('');\n          await suite.expectHiddenDropdown();\n        });\n\n        describe('with should sort', () => {\n          test('on', async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, 'remove-button-with-sorting-on');\n            await suite.startWithClick();\n            await suite.expectVisibleDropdown();\n\n            await suite.items.getByRole('button', { name: 'Remove item' }).last().click();\n            await suite.advanceClock();\n\n            const firstChoice = suite.choices.first();\n            await expect(firstChoice).toHaveText('Choice 1');\n            const lastChoice = suite.choices.last();\n            await expect(lastChoice).toHaveText('Choice 4');\n\n            await suite.escapeKey();\n            await suite.expectHiddenDropdown();\n          });\n\n          test('off', async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, 'remove-button-with-sorting-off');\n            await suite.startWithClick();\n            await suite.expectVisibleDropdown();\n\n            await suite.items.getByRole('button', { name: 'Remove item' }).last().click();\n            await suite.advanceClock();\n\n            const firstChoice = suite.choices.first();\n            await expect(firstChoice).toHaveText('Choice 4');\n            const lastChoice = suite.choices.last();\n            await expect(lastChoice).toHaveText('Choice 1');\n\n            await suite.escapeKey();\n            await suite.expectHiddenDropdown();\n          });\n        });\n      });\n    });\n\n    describe('duplicate-items', () => {\n      test('shows all duplicate items', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, 'duplicate-items-allowed');\n        await suite.startWithClick();\n\n        await expect(suite.selectableChoices).toHaveCount(5);\n      });\n      test('shows unique items', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, 'duplicate-items-disallowed');\n        await suite.startWithClick();\n\n        await expect(suite.selectableChoices).toHaveCount(3);\n      });\n    });\n\n    describe('no choices', () => {\n      const testId = 'no-choices';\n      test('shows no choices banner', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n\n        await expect(suite.selectableChoices).toHaveCount(0);\n        await suite.expectVisibleNoticeHtml('No choices to choose from', true);\n      });\n    });\n\n    describe('Selected choices rendering', () => {\n      test('Skip render selected choices', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, 'renderSelectedChoices-true');\n        await suite.startWithClick();\n\n        await expect(suite.selectableChoices).toHaveCount(1);\n      });\n    });\n\n    describe('No choices (besides selected)', () => {\n      const testId = 'no-choices2';\n      test('shows no choices banner', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n\n        await expect(suite.selectableChoices).toHaveCount(0);\n        await suite.expectVisibleNoticeHtml('No choices to choose from', true);\n      });\n\n      test('shows no results banner and then no choices banner', async ({ page, bundle }) => {\n        const invalidLabel = 'faergge';\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n\n        await suite.typeText(invalidLabel);\n        await expect(suite.selectableChoices).toHaveCount(0);\n        await suite.expectVisibleNoticeHtml('No results found', true);\n\n        await suite.typeText('');\n        await expect(suite.selectableChoices).toHaveCount(0);\n        await suite.expectVisibleNoticeHtml('No choices to choose from', true);\n      });\n    });\n\n    describe('disabled choice', () => {\n      const testId = 'disabled-choice';\n      const firstChoice = 'Choice 1';\n      test('does not change selected choice', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n\n        await suite.expectedItemCount(1);\n        await suite.expectedValue(firstChoice);\n\n        const choice = suite.choices.last();\n        await expect(choice).toBeDisabled();\n        await choice.click({ force: true });\n\n        await suite.expectedItemCount(1);\n        await suite.expectedValue(firstChoice);\n      });\n    });\n\n    describe('Disabled first choice by options', () => {\n      const testId = 'disabled-first-choice-via-options';\n      const firstChoice = 'Choice 2';\n      test('does not change selected choice', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n\n        await suite.expectedItemCount(1);\n        await suite.expectedValue(firstChoice);\n\n        const choice = suite.choices.first();\n        await expect(choice).toBeDisabled();\n        await choice.click({ force: true });\n\n        await suite.expectedItemCount(1);\n        await suite.expectedValue(firstChoice);\n      });\n    });\n\n    describe('disabled via attribute', () => {\n      const testId = 'disabled-via-attr';\n      test('disables the search input', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.start();\n        await suite.wrapper.click({ force: true });\n\n        await expect(suite.wrapper).toBeDisabled();\n        await suite.expectHiddenDropdown();\n      });\n    });\n\n    describe('disabled via fieldset', () => {\n      const testId = 'disabled-via-fieldset';\n      test('disables the search input', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.start();\n        await suite.wrapper.click({ force: true });\n\n        await expect(suite.wrapper).toBeDisabled();\n        await suite.expectHiddenDropdown();\n      });\n    });\n\n    describe('prepend/append', () => {\n      const testId = 'prepend-append';\n      const textInput = 'Choice 1';\n      test('prepends and appends value to inputted value', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n\n        const item = suite.items.first();\n        await expect(item).toHaveText(textInput);\n        await expect(item).toHaveAttribute('data-value', `before-${textInput}-after`);\n      });\n    });\n\n    describe('render choice limit', () => {\n      const testId = 'render-choice-limit';\n      test('only displays given number of choices in the dropdown', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n\n        expect(await suite.choices.count()).toEqual(1);\n      });\n    });\n\n    describe('search disabled', () => {\n      const testId = 'search-disabled';\n      test('does not display a search input', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n\n        await expect(suite.input).toHaveCount(0);\n      });\n\n      test('allows selecting choices from dropdown', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n\n        const choice = suite.choices.last();\n        const text = await choice.innerText();\n        await expect(choice).toBeEnabled();\n        await choice.click();\n\n        await suite.expectedItemCount(1);\n        await suite.expectedValue(text);\n        await suite.expectHiddenDropdown();\n      });\n    });\n\n    describe('search floor', () => {\n      const testId = 'search-floor';\n      describe('on input', () => {\n        describe('search floor not reached', () => {\n          test('displays choices not filtered by inputted value', async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.startWithClick();\n\n            const searchTerm = 'item 2';\n            await suite.typeText(searchTerm);\n            await suite.expectVisibleDropdown();\n            await expect(suite.choices.first()).not.toHaveText(searchTerm);\n          });\n        });\n\n        describe('search floor reached', () => {\n          test('displays choices filtered by inputted value', async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.startWithClick();\n\n            const searchTerm = 'Choice 2';\n\n            await suite.typeText(searchTerm);\n            await suite.expectVisibleDropdown();\n            await expect(suite.choices.first()).toHaveText(searchTerm);\n          });\n        });\n      });\n    });\n\n    [\n      {\n        name: 'empty option value',\n        testId: 'placeholder-via-option-value',\n      },\n      {\n        name: 'option attribute',\n        testId: 'placeholder-via-option-attr',\n      },\n      {\n        name: 'data attribute',\n        testId: 'placeholder-via-data-attr',\n      },\n    ].forEach((arg) => {\n      const { testId } = arg;\n      describe(`Placeholder via ${arg.name}`, () => {\n        describe('when no choice has been selected', () => {\n          test('displays a placeholder', async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.startWithClick();\n\n            await suite.expectedItemCount(0);\n            await suite.expectedValue('');\n\n            const item = suite.itemsWithPlaceholder.first();\n            await expect(item).toHaveClass(/choices__placeholder/);\n            await expect(item).toHaveText('I am a placeholder');\n          });\n        });\n\n        describe('when a choice has been selected', () => {\n          test('does not display a placeholder', async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.startWithClick();\n\n            const choice = suite.selectableChoices.first();\n            await choice.click();\n\n            const item = suite.itemsWithPlaceholder.first();\n            await expect(item).not.toHaveClass(/choices__placeholder/);\n            await expect(item).not.toHaveText('I am a placeholder');\n            await suite.expectHiddenDropdown();\n          });\n        });\n\n        describe('when choice list is open', () => {\n          if (testId === 'placeholder-via-data-attr') {\n            test('does not displays the placeholder choice first', async ({ page, bundle }) => {\n              const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n              await suite.startWithClick();\n\n              const choice = suite.choices.first();\n              await expect(choice).not.toHaveClass(/choices__placeholder/);\n              await expect(choice).not.toHaveText('I am a placeholder');\n            });\n          } else {\n            test('displays the placeholder choice first', async ({ page, bundle }) => {\n              const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n              await suite.startWithClick();\n\n              const choice = suite.choices.first();\n              await expect(choice).toHaveClass(/choices__placeholder/);\n              await expect(choice).toHaveText('I am a placeholder');\n            });\n          }\n        });\n      });\n    });\n\n    describe('remote data', () => {\n      const testId = 'remote-data';\n      test('checking placeholder values', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n\n        const jsonLoad = page.waitForResponse('**/data.json');\n        const stopJsonWaiting = await suite.delayData();\n        await suite.start();\n\n        await expect(suite.itemList.first()).toHaveText('Loading...');\n\n        stopJsonWaiting();\n        await jsonLoad;\n        await suite.selectByClick();\n\n        const firstItem = suite.itemsWithPlaceholder.first();\n        await expect(firstItem).toHaveClass(/choices__placeholder/);\n        await expect(firstItem).toHaveText('I am a placeholder');\n        await expect(suite.selectableChoices).toHaveCount(10);\n      });\n\n      const testIdForDisabled = 'remote-disabled-data';\n      test('checking disabled items are shown in dropdown', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testIdForDisabled);\n\n        const jsonLoad = page.waitForResponse('**/disabled-data.json');\n        const stopJsonWaiting = await suite.delayDisaabledData();\n        await suite.start();\n\n        await expect(suite.itemList.first()).toHaveText('Loading...');\n\n        stopJsonWaiting();\n        await jsonLoad;\n        await suite.selectByClick();\n\n        const firstItem = suite.itemsWithPlaceholder.first();\n        await expect(firstItem).toHaveClass(/choices__placeholder/);\n        await expect(firstItem).toHaveText('I am a placeholder');\n\n        const lastChoice = suite.selectableChoices.last();\n        await expect(lastChoice).toHaveClass(/choices__item--disabled/);\n        await expect(lastChoice).toHaveText('Disabled Label 10');\n\n        await expect(suite.selectableChoices.locator(':not(.choices__item--disabled)')).toHaveCount(0);\n        await expect(suite.selectableChoices.locator('+ .choices__item--disabled')).toHaveCount(9);\n      });\n    });\n\n    describe('scrolling dropdown', () => {\n      const testId = 'scrolling-dropdown';\n      test('shows partial choices list', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n\n        await expect(suite.selectableChoices).toHaveCount(15);\n        // @todo determine how to assert items\n        // await expect(suite.selectableChoices.filter({ has: page.locator(':scope:visible') })).toHaveCount(8);\n      });\n    });\n\n    describe('choice groups', () => {\n      describe('just groups', () => {\n        const testId = 'groups';\n        test('displays', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n\n          await expect(suite.dropdown.locator('.choices__group[data-group]')).toHaveCount(2);\n        });\n      });\n\n      describe('groups and choices', () => {\n        const testId = 'mixed-groups';\n        test('displays', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n\n          await expect(suite.dropdown.locator('.choices__group[data-group]')).toHaveCount(1);\n          expect(await suite.dropdown.locator('.choices__item--choice[data-group-id]').count()).toEqual(1);\n          expect(await suite.dropdown.locator('.choices__item--choice:not([data-group-id])').count()).toBeGreaterThan(\n            1,\n          );\n        });\n      });\n    });\n\n    describe('parent/child', () => {\n      const testId = 'parent-child';\n      describe('selecting \"Parent choice 2\"', () => {\n        test('enables/disables the child Choices instance', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.start();\n\n          const parent = suite.group.locator('.choices').nth(0);\n          const child = suite.group.locator('.choices').nth(1);\n          await expect(parent).toBeEnabled();\n          await expect(child).toBeDisabled();\n\n          await parent.click();\n          await expect(suite.dropdown.first()).toBeVisible();\n          const parentChoices = parent.locator('.choices__item:not(.choices__placeholder)');\n\n          await parentChoices.filter({ hasText: 'Parent choice 2' }).click();\n\n          await expect(child).toBeEnabled();\n\n          await parent.click();\n          await expect(suite.dropdown.first()).toBeVisible();\n          const choice = parentChoices.filter({ hasText: 'Parent choice 3' });\n          await choice.click();\n\n          await expect(child).toBeDisabled();\n        });\n      });\n    });\n\n    describe('custom properties via config', () => {\n      const testId = 'custom-properties';\n      const cities = [\n        {\n          country: 'Germany',\n          city: 'Berlin',\n        },\n        {\n          country: 'United Kingdom',\n          city: 'London',\n        },\n        {\n          country: 'Portugal',\n          city: 'Lisbon',\n        },\n      ];\n      describe('on input', () => {\n        cities.forEach(({ country, city }) => {\n          test(`filters choices - ${country} = ${city}`, async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.startWithClick();\n            await suite.typeText(country);\n            await suite.expectVisibleDropdown();\n\n            const choice = suite.selectableChoices.first();\n            await expect(choice).toHaveText(city);\n          });\n\n          test(`filters choices - ${city}`, async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.startWithClick();\n            await suite.typeText(city);\n            await suite.expectVisibleDropdown();\n\n            const choice = suite.selectableChoices.first();\n            await expect(choice).toHaveText(city);\n          });\n        });\n      });\n\n      describe('on paste', () => {\n        // playwright lacks clipboard isolation, so use serial mode to try to work around it.\n        // https://github.com/microsoft/playwright/issues/13097\n        describe.configure({ mode: 'serial', timeout: 30000 });\n\n        cities.forEach(({ country, city }) => {\n          test(`filters choices - ${country} = ${city}`, async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.startWithClick();\n\n            await suite.pasteText(country);\n\n            const choice = suite.selectableChoices.first();\n            await expect(choice).toHaveText(city);\n          });\n\n          test(`filters choices - ${city}`, async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.startWithClick();\n\n            await suite.pasteText(city);\n\n            const choice = suite.selectableChoices.first();\n            await expect(choice).toHaveText(city);\n          });\n        });\n      });\n    });\n\n    describe('custom properties via html', () => {\n      const testId = 'custom-properties-html';\n      describe('on input', () => {\n        [\n          {\n            searchText: 'fantastic',\n            label: 'Label Three',\n          },\n          {\n            searchText: 'foo',\n            label: 'Label Four',\n          },\n        ].forEach(({ searchText, label }) => {\n          test(`filters choices - ${searchText} = ${label}`, async ({ page, bundle }) => {\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.startWithClick();\n            await suite.typeText(searchText);\n            await suite.expectVisibleDropdown();\n\n            const choice = suite.selectableChoices.first();\n            await expect(choice).toHaveText(label);\n          });\n        });\n      });\n    });\n\n    describe('non-string values', () => {\n      const testId = 'non-string-values';\n      test('displays expected amount of choices in dropdown', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n\n        await expect(suite.selectableChoices).toHaveCount(4);\n      });\n\n      test('allows selecting choices from dropdown', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n\n        const choice = suite.selectableChoices.first();\n        const choiceText = await choice.textContent();\n        expect(choiceText).toBeTruthy();\n        await choice.click();\n\n        await expect(suite.items.first()).toHaveText(choiceText as string);\n      });\n    });\n\n    describe('within form', () => {\n      const testId = 'within-form';\n      describe('selecting choice', () => {\n        describe('on enter key', () => {\n          test('does not submit form', async ({ page, bundle }) => {\n            let submit = false;\n            await page.route(page.url(), (route) => {\n              submit = true;\n\n              return route.abort();\n            });\n\n            const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n            await suite.startWithClick();\n            await suite.expectVisibleDropdown();\n\n            const choice = suite.choices.first();\n            const text = await choice.innerText();\n            await expect(choice).toBeEnabled();\n            await choice.click();\n            await suite.advanceClock();\n\n            await suite.expectedItemCount(1);\n            await suite.expectedValue(text);\n            expect(submit).toEqual(false);\n            await suite.expectHiddenDropdown();\n          });\n        });\n      });\n    });\n\n    describe('dynamically setting choice by value', () => {\n      const dynamicallySelectedChoiceValue = 'Choice 2';\n      const testId = 'set-choice-by-value';\n      test('selects choice', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n\n        await expect(suite.items).toHaveText(dynamicallySelectedChoiceValue);\n        await suite.expectedItemCount(1);\n      });\n\n      test('does not remove choice from dropdown list', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n\n        await expect(suite.getChoiceWithText(dynamicallySelectedChoiceValue)).toHaveCount(1);\n      });\n\n      test('updates the value of the original input', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n\n        await suite.expectedValue(dynamicallySelectedChoiceValue);\n      });\n    });\n\n    describe('searching by label only', () => {\n      const testId = 'search-by-label';\n      test('gets zero results when searching by value', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n        await suite.typeText('item2');\n\n        await suite.expectVisibleNoticeHtml('No results found', true);\n      });\n\n      test('gets a result when searching by label', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n        await suite.typeText('label1');\n        await suite.expectVisibleDropdown();\n        await suite.enterKey();\n        await suite.expectHiddenDropdown();\n\n        await expect(suite.items.filter({ hasText: 'label1' })).not.toHaveCount(0);\n      });\n    });\n\n    describe('html allowed', () => {\n      const textInput = 'testing';\n      const htmlInput = `<b>${textInput}</b>`;\n      const escapedInput = sanitise(htmlInput);\n      describe('set to undefined', () => {\n        const testId = 'allowhtml-undefined';\n        test('does not show html', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n          await suite.typeText(htmlInput);\n          await suite.expectVisibleNoticeHtml(`Press Enter to add <b>\"${escapedInput}\"</b>`);\n          await suite.enterKey();\n\n          await expect(suite.items.first()).toHaveText(htmlInput);\n        });\n      });\n\n      describe('set to true', () => {\n        const testId = 'allowhtml-true';\n        test('does not show html as text', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n          await suite.typeText(htmlInput);\n          await suite.expectVisibleNoticeHtml(`Press Enter to add <b>\"${escapedInput}\"</b>`);\n          await suite.enterKey();\n\n          await expect(suite.items.first()).toHaveText(textInput);\n        });\n      });\n\n      describe('set to true - except user input', () => {\n        const testId = 'allowhtml-true-userinput-false';\n        test('does not show html as text', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n          await suite.typeText(htmlInput);\n          await suite.expectVisibleNoticeHtml(`Press Enter to add <b>\"${escapedInput}\"</b>`);\n          await suite.enterKey();\n\n          await expect(suite.items.first()).toHaveText(htmlInput);\n        });\n      });\n\n      describe('set to false', () => {\n        const testId = 'allowhtml-false';\n        test('does not show html as text', async ({ page, bundle }) => {\n          const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n          await suite.startWithClick();\n          await suite.typeText(htmlInput);\n          await suite.expectVisibleNoticeHtml(`Press Enter to add <b>\"${escapedInput}\"</b>`);\n          await suite.enterKey();\n\n          await expect(suite.items.first()).toHaveText(htmlInput);\n        });\n      });\n    });\n\n    describe('re-initialising a choices instance', () => {\n      const testId = 'new-destroy-init';\n      const testvalue = 'Choice 2';\n      test('preserves the choices & items lists', async ({ page, bundle }) => {\n        let suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n        await suite.typeTextAndEnter(testvalue);\n        await suite.expectHiddenDropdown();\n        await suite.expectedItemCount(1);\n        await suite.expectChoiceCount(3);\n\n        await suite.expectHiddenDropdown();\n\n        await suite.group.locator('.destroy').click({ force: true });\n        await suite.advanceClock();\n\n        await expect(suite.group.locator('select > optgroup > option')).toHaveCount(1);\n        await expect(suite.group.locator('select > option')).toHaveCount(2);\n\n        await suite.group.locator('.init').click({ force: true });\n        await suite.advanceClock();\n\n        suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.expectedItemCount(1);\n        await suite.expectChoiceCount(3);\n        await suite.expectedValue(testvalue);\n      });\n    });\n\n    describe('autocomplete', () => {\n      const testId = 'autocomplete';\n      test('Expected notice results', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n        await suite.typeText('f');\n        await expect(suite.input).toHaveValue('f');\n        await suite.expectVisibleNoticeHtml('No results found');\n        await suite.typeText('fo');\n        await expect(suite.input).toHaveValue('fo');\n        await suite.expectVisibleDropdownWithItem('Found');\n\n        await suite.keyPress('Backspace');\n        await suite.keyPress('Backspace');\n        await suite.expectVisibleNoticeHtml('No choices to choose from');\n      });\n    });\n\n    describe('Clear choices on add item', () => {\n      const testId = 'clear-on-add';\n      test('Expected items', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, testId);\n        await suite.startWithClick();\n        await suite.expectChoiceCount(2);\n\n        await suite.choices.last().click();\n        await suite.advanceClock();\n        await suite.expectedItemCount(1);\n        await suite.expectChoiceCount(1);\n      });\n    });\n\n    describe('setChoices', () => {\n      test('Expected selected to be preserved', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, 'set-choices-preserve');\n        await suite.start();\n\n        await suite.expectHiddenDropdown();\n        await suite.expectedValue('Choice 2');\n        await suite.expectedItemCount(1);\n        await suite.expectChoiceCount(3);\n      });\n\n      test('Expected selected to be preserved (no duplicates)', async ({ page, bundle }) => {\n        const suite = new SelectTestSuit(page, bundle, testUrl, 'set-choices-preserve-no-dupes');\n        await suite.start();\n\n        await suite.expectHiddenDropdown();\n        await suite.expectedValue('Choice 2');\n        await suite.expectedItemCount(1);\n        await suite.expectChoiceCount(2);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test-e2e/tests/text.spec.ts",
    "content": "import { expect } from '@playwright/test';\nimport { test } from '../bundle-test';\nimport { TextTestSuit } from '../text-test-suit';\nimport { sanitise } from '../../src/scripts/lib/utils';\n\nconst { describe } = test;\n\nconst testUrl = '/test/text/index.html';\nconst textInput = 'testing';\n\ndescribe(`Choices - text element`, () => {\n  describe('scenarios', () => {\n    describe('basic', () => {\n      const testId = 'basic';\n      describe('adding items', () => {\n        test('allows me to input items', async ({ page, bundle }) => {\n          const suite = new TextTestSuit(page, bundle, testUrl, testId);\n          await suite.start(textInput);\n          await suite.expectHiddenDropdown();\n\n          await suite.expectedValue(textInput);\n        });\n\n        test('Verify text mode has no choices UI', async ({ page, bundle }) => {\n          const suite = new TextTestSuit(page, bundle, testUrl, testId);\n          await suite.start(textInput);\n          await suite.enterKey();\n          await expect(suite.dropdown).not.toHaveText('No choices to choose from');\n        });\n\n        describe('inputting data', () => {\n          test('shows a dropdown prompt', async ({ page, bundle }) => {\n            const suite = new TextTestSuit(page, bundle, testUrl, testId);\n            await suite.start();\n            await suite.typeText(textInput);\n\n            await suite.expectVisibleNoticeHtml(`Press Enter to add <b>\"${textInput}\"</b>`);\n          });\n        });\n      });\n    });\n\n    describe('editing items', () => {\n      const testId = 'edit-items';\n      describe('on back space', () => {\n        test('allows me to change my entry', async ({ page, bundle }) => {\n          const suite = new TextTestSuit(page, bundle, testUrl, testId);\n          await suite.start(textInput);\n          await suite.backspaceKey();\n          await suite.typeTextAndEnter('-edited');\n          await suite.expectHiddenDropdown();\n\n          await expect(suite.itemList).toHaveText('-edited');\n        });\n      });\n\n      describe('on cmd+a', () => {\n        test('highlights all items', async ({ page, bundle }) => {\n          const suite = new TextTestSuit(page, bundle, testUrl, testId);\n          await suite.start(textInput);\n          await suite.ctrlA();\n          await suite.expectHiddenDropdown();\n\n          expect(await suite.itemList.locator('.is-highlighted').count()).toEqual(1);\n        });\n\n        describe('on backspace', () => {\n          test('clears all inputted values', async ({ page, bundle }) => {\n            const suite = new TextTestSuit(page, bundle, testUrl, testId);\n            await suite.start(textInput);\n            await suite.ctrlA();\n            await suite.backspaceKey();\n            await suite.expectHiddenDropdown();\n\n            expect(await suite.itemList.locator('.is-highlighted').count()).toEqual(0);\n          });\n        });\n      });\n    });\n\n    describe('remove button', () => {\n      const testId = 'remove-button';\n      describe('on click', () => {\n        test('removes respective choice', async ({ page, bundle }) => {\n          const suite = new TextTestSuit(page, bundle, testUrl, testId);\n          await suite.start(textInput);\n          await suite.expectHiddenDropdown();\n\n          await suite.expectedItemCount(1);\n\n          const button = suite.itemList.getByRole('button');\n          await button.focus();\n          await button.click();\n\n          await suite.expectedItemCount(0);\n          await suite.expectedValue('');\n        });\n      });\n    });\n\n    describe('unique values only', () => {\n      const testId = 'unique-values';\n      describe('unique values', () => {\n        test('only allows me to input unique values', async ({ page, bundle }) => {\n          const suite = new TextTestSuit(page, bundle, testUrl, testId);\n          await suite.start(textInput);\n          await suite.expectHiddenDropdown();\n\n          await suite.typeTextAndEnter(textInput);\n\n          await suite.expectedItemCount(1);\n          await suite.expectVisibleNoticeHtml(`Only unique values can be added`);\n        });\n      });\n    });\n\n    describe('html allowed', () => {\n      const htmlInput = `<b>${textInput}</b>`;\n      const escapedInput = sanitise(htmlInput);\n      describe('set to undefined', () => {\n        const testId = 'allowhtml-undefined';\n        test('does not show html', async ({ page, bundle }) => {\n          const suite = new TextTestSuit(page, bundle, testUrl, testId);\n          await suite.start();\n          await suite.typeText(htmlInput);\n          await suite.expectVisibleNoticeHtml(`Press Enter to add <b>\"${escapedInput}\"</b>`);\n          await suite.enterKey();\n\n          await expect(suite.items.first()).toHaveText('<b>Mason Rogers</b>');\n          await expect(suite.items.last()).toHaveText(htmlInput);\n        });\n      });\n\n      describe('set to true', () => {\n        const testId = 'allowhtml-true';\n        test('does not show html as text', async ({ page, bundle }) => {\n          const suite = new TextTestSuit(page, bundle, testUrl, testId);\n          await suite.start();\n          await suite.typeText(htmlInput);\n          await suite.expectVisibleNoticeHtml(`Press Enter to add <b>\"${escapedInput}\"</b>`);\n          await suite.enterKey();\n\n          await expect(suite.items.first()).toHaveText('Mason Rogers');\n          await expect(suite.items.last()).toHaveText(textInput);\n        });\n      });\n\n      describe('set to true - except user input', () => {\n        const testId = 'allowhtml-true-userinput-false';\n        test('does not show html as text', async ({ page, bundle }) => {\n          const suite = new TextTestSuit(page, bundle, testUrl, testId);\n          await suite.start();\n          await suite.typeText(htmlInput);\n          await suite.expectVisibleNoticeHtml(`Press Enter to add <b>\"${escapedInput}\"</b>`);\n          await suite.enterKey();\n\n          await expect(suite.items.first()).toHaveText('Mason Rogers');\n          await expect(suite.items.last()).toHaveText(htmlInput);\n        });\n      });\n\n      describe('set to false', () => {\n        const testId = 'allowhtml-false';\n        test('does not show html as text', async ({ page, bundle }) => {\n          const suite = new TextTestSuit(page, bundle, testUrl, testId);\n          await suite.start();\n          await suite.typeText(htmlInput);\n          await suite.expectVisibleNoticeHtml(`Press Enter to add <b>\"${escapedInput}\"</b>`);\n          await suite.enterKey();\n\n          await expect(suite.items.first()).toHaveText('<b>Mason Rogers</b>');\n          await expect(suite.items.last()).toHaveText(htmlInput);\n        });\n      });\n    });\n\n    describe('input limit', () => {\n      const testId = 'input-limit';\n      const inputLimit = 5;\n\n      test('does not let me input more than 5 choices', async ({ page, bundle }) => {\n        const suite = new TextTestSuit(page, bundle, testUrl, testId);\n        await suite.start();\n        for (let index = 0; index < inputLimit; index++) {\n          await suite.typeTextAndEnter(textInput);\n          await suite.expectHiddenDropdown();\n        }\n        await suite.typeText(textInput);\n\n        expect(await suite.items.count()).toEqual(inputLimit);\n        await suite.expectVisibleNoticeHtml(`Only ${inputLimit} values can be added`);\n\n        await suite.typeText(textInput);\n        expect(await suite.items.count()).toEqual(inputLimit);\n        await suite.expectVisibleNoticeHtml(`Only ${inputLimit} values can be added`);\n      });\n    });\n\n    describe('add item filter', () => {\n      const testId = 'add-item-filter';\n      describe('inputting a value that satisfies the filter', () => {\n        const input = 'joe@bloggs.com';\n\n        test('allows me to add choice', async ({ page, bundle }) => {\n          const suite = new TextTestSuit(page, bundle, testUrl, testId);\n          await suite.start(input);\n          await suite.expectHiddenDropdown();\n\n          await expect(suite.itemList).toHaveText(input);\n        });\n      });\n\n      describe('inputting a value that does not satisfy the regex', () => {\n        test('displays dropdown prompt', async ({ page, bundle }) => {\n          const suite = new TextTestSuit(page, bundle, testUrl, testId);\n          await suite.start(`this is not an email address`);\n\n          await suite.expectVisibleNoticeHtml(`Only values matching specific conditions can be added`);\n        });\n      });\n    });\n\n    describe('adding items disabled', () => {\n      const testId = 'adding-items-disabled';\n      test('does not allow me to input data', async ({ page, bundle }) => {\n        const suite = new TextTestSuit(page, bundle, testUrl, testId);\n        await suite.start();\n        await suite.expectHiddenDropdown();\n\n        await expect(suite.input).toBeDisabled();\n      });\n    });\n\n    describe('disabled via fieldset', () => {\n      const testId = 'disabled-via-fieldset';\n      test('does not allow me to input data', async ({ page, bundle }) => {\n        const suite = new TextTestSuit(page, bundle, testUrl, testId);\n        await suite.start();\n        await suite.expectHiddenDropdown();\n\n        await expect(suite.input).toBeDisabled();\n      });\n    });\n\n    describe('disabled via attribute', () => {\n      const testId = 'disabled-via-attr';\n      test('does not allow me to input data', async ({ page, bundle }) => {\n        const suite = new TextTestSuit(page, bundle, testUrl, testId);\n        await suite.start();\n        await suite.expectHiddenDropdown();\n\n        await expect(suite.input).toBeDisabled();\n      });\n    });\n\n    describe('prepend/append', () => {\n      const testId = 'prepend-append';\n      test('prepends and appends value to inputted value', async ({ page, bundle }) => {\n        const suite = new TextTestSuit(page, bundle, testUrl, testId);\n        await suite.start(textInput);\n        await suite.expectHiddenDropdown();\n\n        const item = suite.items.first();\n        await expect(item).toHaveText(textInput);\n        await expect(item).toHaveAttribute('data-value', `before-${textInput}-after`);\n      });\n    });\n\n    describe('pre-populated choices', () => {\n      const testId = 'prepopulated';\n      test('pre-populates choices', async ({ page, bundle }) => {\n        const suite = new TextTestSuit(page, bundle, testUrl, testId);\n        await suite.start();\n        await suite.expectHiddenDropdown();\n\n        expect(await suite.items.count()).toEqual(2);\n        await expect(suite.items.first()).toHaveText('Josh Johnson');\n        await expect(suite.items.last()).toHaveText('Joe Bloggs');\n      });\n    });\n\n    describe('placeholder', () => {\n      const testId = 'placeholder';\n      describe('when no value has been inputted', () => {\n        test('displays a placeholder', async ({ page, bundle }) => {\n          const suite = new TextTestSuit(page, bundle, testUrl, testId);\n          await suite.start();\n          await suite.expectHiddenDropdown();\n\n          await expect(suite.input).toHaveAttribute('placeholder', 'I am a placeholder');\n        });\n      });\n    });\n\n    describe('within form', () => {\n      const testId = 'within-form';\n      describe('inputting item', () => {\n        describe('on enter key', () => {\n          test('does not submit form', async ({ page, bundle }) => {\n            let submit = false;\n            await page.route(page.url(), (route) => {\n              submit = true;\n\n              return route.abort();\n            });\n\n            const suite = new TextTestSuit(page, bundle, testUrl, testId);\n            await suite.start(textInput);\n            await suite.expectHiddenDropdown();\n\n            await suite.expectedValue(textInput);\n            expect(submit).toEqual(false);\n          });\n        });\n      });\n    });\n\n    describe('shadow-dom - basic', () => {\n      const testId = 'shadow-dom';\n      describe('adding items', () => {\n        test('allows me to input items', async ({ page, bundle }) => {\n          const suite = new TextTestSuit(page, bundle, testUrl, testId);\n          await suite.start(textInput);\n          await suite.expectHiddenDropdown();\n\n          await suite.expectedValue(textInput);\n        });\n\n        describe('inputting data', () => {\n          test('shows a dropdown prompt', async ({ page, bundle }) => {\n            const suite = new TextTestSuit(page, bundle, testUrl, testId);\n            await suite.start();\n            await suite.typeText(textInput);\n\n            await suite.expectVisibleNoticeHtml(`Press Enter to add <b>\"${textInput}\"</b>`);\n          });\n        });\n      });\n    });\n\n    describe('re-initialising a choices instance', () => {\n      const testId = 'new-destroy-init';\n      test('preserves the choices & items lists', async ({ page, bundle }) => {\n        let suite = new TextTestSuit(page, bundle, testUrl, testId);\n        await suite.start(textInput);\n        await suite.expectHiddenDropdown();\n\n        await suite.expectedItemCount(1);\n\n        await suite.group.locator('.destroy').click({ force: true });\n        await suite.advanceClock();\n\n        await suite.group.locator('.init').click({ force: true });\n        await suite.advanceClock();\n\n        suite = new TextTestSuit(page, bundle, testUrl, testId);\n        await suite.expectedItemCount(1);\n        await suite.expectedValue(textInput);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "test-e2e/text-test-suit.ts",
    "content": "import { type Locator, type Page } from '@playwright/test';\nimport { TestSuit } from './test-suit';\n\nexport class TextTestSuit extends TestSuit {\n  readonly wrappedInput: Locator;\n\n  constructor(page: Page, choicesBundle: string | undefined, url: string, testId: string) {\n    super(page, choicesBundle, url, testId);\n\n    this.wrappedInput = this.group.locator('input[hidden]');\n  }\n\n  getWrappedElement(): Locator {\n    return this.wrappedInput;\n  }\n}\n"
  },
  {
    "path": "test-e2e/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"module\": \"es6\",\n    \"lib\": [\"es2017\", \"dom\"],\n    \"target\": \"ES2020\",\n    \"moduleResolution\": \"bundler\",\n    \"allowSyntheticDefaultImports\": true,\n    \"resolveJsonModule\": true,\n    \"esModuleInterop\": true,\n    \"strict\": false,\n    \"noImplicitAny\": false,\n    \"allowJs\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"strictNullChecks\": true,\n    \"newLine\": \"lf\",\n    \"declaration\": false,\n    \"declarationMap\": false,\n    \"types\": [\"@types/node\"],\n  },\n  \"include\": [\".\", \"../src\"],\n  \"exclude\": [\"**/node_modules\", \"**/public\"]\n}\n"
  },
  {
    "path": "vitest.config.ts",
    "content": "import { defineConfig } from 'vitest/config';\n\nexport default defineConfig({\n  test: {\n    globals: true,\n    environment: 'jsdom',\n    setupFiles: ['./test/setupFiles/window-matchMedia.ts'],\n    include: ['test/**/*.{test,spec}.?(c|m)[jt]s?(x)'],\n  },\n  esbuild: {\n    target: 'es2017',\n  },\n});\n"
  }
]