[
  {
    "path": ".eslintrc.json",
    "content": "{\n  \"env\": {\n      \"browser\": true,\n      \"es6\": true\n  },\n  \"extends\": [\n    \"plugin:vue/vue3-recommended\",\n    \"plugin:@typescript-eslint/recommended\",\n    \"airbnb-typescript/base\"\n  ],\n  \"parser\": \"vue-eslint-parser\",\n  \"parserOptions\": {\n      \"ecmaVersion\": 2018,\n      \"parser\": \"@typescript-eslint/parser\",\n      \"sourceType\": \"module\",\n      \"project\": \"tsconfig.json\",\n      \"tsconfigRootDir\": \"./\",\n      \"extraFileExtensions\": [ \".vue\" ]\n  },\n  \"plugins\": [\n    \"vue\",\n    \"@typescript-eslint\",\n    \"tree-shaking\"\n  ],\n  \"rules\": {\n    \"max-len\": \"off\",\n    \"import/extensions\": \"off\",\n    \"import/prefer-default-export\": \"off\",\n    \"import/no-extraneous-dependencies\": \"off\",\n    \"@typescript-eslint/no-non-null-assertion\": \"off\",\n    \"tree-shaking/no-side-effects-in-initialization\": 2\n  },\n  \"overrides\": [\n    {\n      \"files\": [\"*.spec.ts\", \"src/main.ts\", \"src/development/*\"],\n      \"rules\": {\n        \"tree-shaking/no-side-effects-in-initialization\": \"off\"\n      }\n    }\n  ]\n}\n\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "# These are supported funding model platforms\ngithub: variantjs\ncustom: https://www.buymeacoffee.com/alfonsobries\n"
  },
  {
    "path": ".github/workflows/yarn.yml",
    "content": "name: CI\non: push\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v2\n    - name: Install modules\n      run: yarn\n    - name: Run tests\n      run: yarn test --coverage"
  },
  {
    "path": ".gitignore",
    "content": "node_modules\n.DS_Store\ndist\ndist-ssr\ncoverage\n*.local\nyarn-error.log"
  },
  {
    "path": "README.md",
    "content": "# VariantJS/Vue (PREVIEW)\n\n\n![CI](https://github.com/variantjs/vue/workflows/CI/badge.svg) [![CI](https://github.com/variantjs/vue/actions/workflows/yarn.yml/badge.svg?event=release)](https://github.com/variantjs/vue/actions/workflows/yarn.yml)\n\n\n- Consider that this is a preview and all components are subject to change until I release the final version.\n- If you find any error, typo or have comments feel free to create [an issue](https://github.com/variantjs/vue/issues) or open a PR.\n- Also a friendly reminder to consider [sponsor this project](https://github.com/sponsors/variantjs) there is a lot of work behind, **a lot**.\n- You can track the progress (or even see what tasks are pending if you want to contribute) [here](https://github.com/variantjs/vue/projects/1).\n- Demo: [https://variantjs.netlify.app](https://variantjs.netlify.app)\n  \n\n## Whats new?\n\nMain changes against VueTailwind: \n\n- Smaller bundle\n- Better Typescript integration\n- 100% test coverage\n- Built from scratch with Vue 3 + Vite\n- Simpler code and back to use template syntax\n\nIn general, initial components will be pretty much the same, but some components have new settings. As an example, TDropDown and TRichSelect now have a `teleport` and `teleportTo` prop that allows you to move the content of the dropdown to any place on the DOM by using the new teleport setting from Vue. Also, both now use PopperJS, meaning you can have more control over the dropdown position.\n\nAnother note is that the default theme for some components changed a bit. You can check the new default configuration (theme) in the [@variantjs/core](https://github.com/variantjs/core/blob/main/src/config) source code. [Example for the TRichSelect component.](https://github.com/variantjs/core/blob/main/src/config/TRichSelectConfig.ts)\n\nEverything will be documented, of course, but meanwhile, you can check the source code of the components that is way cleaner and easier to understand.\n\n*Components that are ready to be tested*\n\n- [x] TInput\n- [x] TButton\n- [x] TTextarea\n- [x] TSelect\n- [x] TCheckbox\n- [x] TRadio\n- [x] TAlert\n- [x] TCard\n- [x] TDropdown\n- [x] TInputGroup\n- [x] TRichSelect\n- [x] TTag\n- [x] TModal (^0.0.5)\n- [x] TDialog (^0.0.6)\n- [x] TToggle (^0.0.9)\n\n\n*Next ones:*\n\n- [ ] TDatepicker\n- [ ] TRadioGroup\n- [ ] TCheckboxGroup\n- [ ] TTable\n- [ ] TPagination\n- [ ] More to announce soon...\n\n\n**VarianJS/Vue** is the next version of the [VueTailwind](https://github.com/alfonsobries/vue-tailwind) package built from scratch for Vue 3.\n\nIt includes a set of Vue components created to be customized to adapt to your application's unique design and some other useful function that will help you to make your own components.\n\n### Another UI library?\n\nMost component libraries come with:\n\n- A predefined design that is not easy to adapt to your application (in the case it is possible)\n- A big chunk of CSS files that may conflict with your project and increase the size of your build\n- Some are used by hundreds (or even millions of projects) that end with the same design.\n\nThose libraries are great and make our work easy, but hey, we made a beautiful custom design, right?\n### So what are the alternatives?\n\nWe can create our own CSS framework or use something like [TailwindCSS](https://tailwindcss.com) to define our style. The problem?:\nWe need to repeat long CSS classes over and over\nSome components like modals, date pickers, etc., are tricky.\nWe love to be productive.\n\n### Best of both worlds\n\nThe **VariantJS** components are meant to be customized with custom CSS classes that you can define when you install the library.\n\nPlus, most component settings are configurable, so using this library is like having your personal set of components for your particular needs.\n\nAll that means that with this library, you will be able to:\n\n- Define your components look and feel by defining custom default CSS classes.\n- Add unlimited variants for every specific use case.\n- Override the default value of the props according to your needs.\n- Create different versions of one component with different default settings.\n\n## Installation\n\n### 1. Install the dependencies \n\n```console\nnpm install @variantjs/vue @variantjs/core @popperjs/core body-scroll-lock --save\n``` \n\nOr: \n\n```console\nyarn add @variantjs/vue @variantjs/core @popperjs/core body-scroll-lock\n``` \n\nNotes: \n\n* `@popperjs/core` is only need if you use the `TRichSelect` or `TDropdown` component.\n* `body-scroll-lock` is only need if you use the `TModal` component and the incoming `TDialog` component.\n\n\n## 2. Install TailwindCSS (Optional)\n\nThis library uses TailwindCSS classes by default. Still, it should work with any CSS framework since all the CSS classes are configurable.\n\nTo install TailwindCSS follow his official documentation: [https://tailwindcss.com/docs/installation](https://tailwindcss.com/docs/installation)\n\n#### 2.1 Add the @tailwindcss/forms plugin\n\nThe default theme of this library depends on the `@tailwindcss/forms` plugin. To use it, follow the steps on the plugin source page.\n[https://github.com/tailwindlabs/tailwindcss-forms](https://github.com/tailwindlabs/tailwindcss-forms)\n\n#### 2.1 Add variants for disabled pseudo-class\n\nAlso needed for the default theme and strongly recommended since it adds the ability to use some classes like `disabled:opacity-50 disabled:cursor-not-allowed` to disabled inputs.\n\nSee [https://tailwindcss.com/docs/configuring-variants](https://tailwindcss.com/docs/configuring-variants) on the TailwindCSS docs for more info.\n\nAs a reference, your `tailwind.config.js` may look like this:\n\n```js\nmodule.exports = {\n  variants: {\n    extend: {\n      opacity: ['disabled'],\n      cursor: ['disabled'],\n    },\n  },\n  plugins: [\n    require('@tailwindcss/forms'),\n  ],\n};\n```\n\n## 3. Configure Vue to use VariantJS\n\n```js\nimport { createApp } from 'vue'\nimport App from './App.vue'\nimport { variantJS } from '@variantjs/vue'\n\nconst app = createApp(App)\n\nconst configuration = {\n  //...\n}\n\napp.use(variantJS, configuration)\n\napp.mount('#app')\n\n```\n\nYou can also use `typescript` for type checking:\n\n```ts\nimport { createApp } from 'vue'\nimport App from './App.vue'\nimport { variantJS, VariantJSConfiguration } from '@variantjs/vue'\n\nconst app = createApp(App)\n\nconst configuration: VariantJSConfiguration = {\n  //...\n}\n\napp.use(variantJS, configuration)\n\napp.mount('#app')\n\n```\n\n### 4. Configure your components\n\nConsider this:\n\n1. You can override the default value of all the props or even add any custom attributes.\n2. The format of the configuration is the following:\n```js\n// Inside the main file \n\nconst configuration = {\n  {ComponentName}: {\n    {propsOrAttribute}: {newDefautlValue}\n  },\n  {ComponentName2}: {\n    {propsOrAttribute}: {newDefautlValue}\n  },\n  // ...\n}\n\napp.use(variantJS, configuration)\n// ...\n```\n3. The official documentation for this package is stil a WIP. You can use the the [VueTailwind Docs](https://www.vue-tailwind.com/) as reference but consider that some props were removed or updated, you can also see the source code of the components for more information.\n\n### 5. Import the components you need\n\n```vue\n<template>\n  <t-input v-model=\"val\">\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\nimport { TInput } from '@variantjs/vue'\n\nexport default defineComponent({\n  components: {\n    TInput,\n  },\n  data() {\n    return {\n      val: ''\n    }\n  }\n});\n</script>\n\n```\n\n## Theming\n\nTo apply a custom theme you should play with the `classes`, `fixedClasses`, and `variants` props.\n\nThe `classes` and `fixedClasses` props usually expects an `string` with a CSS class for single-tag components (inputs, button, etc.) and an `object` for more complex components (modals, datepicker, etc) (see component docs for details).\n\nThe `variants` props expects an object where every key represents the variant name and every value the classes that will be used when that variant is applied.\n\n#### Example for a single-tag component: \n\n```js\nconst configuration = {\n  TButton: {\n    // The fixed classes will never change and will be merged with the `classes` value or the active variant\n    fixedClasses: 'focus:outline-none focus:shadow-outline inline-flex items-center transition ease-in-out duration-150',\n    // Classes used when any variant is active\n    classes: 'text-white bg-blue-600 hover:bg-blue-500 focus:border-blue-700 active:bg-blue-700 text-sm font-medium border border-transparent px-3 py-2 rounded-md',\n    variants: {\n      // A red variant of the button (applied when `<t-button variant=\"error\" />`)\n      error: {\n        classes: 'text-white bg-red-600 hover:bg-red-500 focus:border-red-700 active:bg-red-700 text-sm font-medium border border-transparent px-3 py-2 rounded-md',\n      },\n      // A green variant of the button (applied when `<t-button variant=\"success\" />`)\n      success: {\n        classes: 'text-white bg-green-600 hover:bg-green-500 focus:border-green-700 active:bg-green-700 text-sm font-medium border border-transparent px-3 py-2 rounded-md',\n      },\n      // ...unlimited variants\n    }\n    // ...More settings\n  },\n}\n```\n\n#### Example for a complex component: \n\n```js\nconst configuration = {\n  TAlert: {\n    // The fixed classes will never change and will be merged with the `classes` value or the active variant\n    fixedClasses: {\n      wrapper: 'rounded p-4 flex text-sm border-l-4',\n      body: 'flex-grow',\n      close: 'ml-4 rounded',\n      closeIcon: 'h-5 w-5 fill-current'\n    },\n    classes: {\n      wrapper: 'bg-blue-100 border-blue-500',\n      body: 'text-blue-700',\n      close: 'text-blue-700 hover:text-blue-500 hover:bg-blue-200',\n      closeIcon: 'h-5 w-5 fill-current'\n    },\n    variants: {\n      danger: {\n        classes: {\n          wrapper: 'bg-red-100 border-red-500',\n          body: 'text-red-700',\n          close: 'text-red-700 hover:text-red-500 hover:bg-red-200'\n          // Notice that I am not defining the `closeIcon` class since we only\n          // need to write the classes we want to override\n        },\n      },\n    },\n  },\n}\n```\n\nWill continue...\n"
  },
  {
    "path": "index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"UTF-8\" />\n    <link rel=\"icon\" href=\"/favicon.ico\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n    <title>Vite App</title>\n  </head>\n  <body>\n    <div id=\"app\"></div>\n    <script type=\"module\" src=\"/src/main.ts\"></script>\n  </body>\n</html>\n"
  },
  {
    "path": "jest.config.js",
    "content": "module.exports = {\n  testEnvironment: 'jsdom',\n  preset: '@vue/cli-plugin-unit-jest/presets/typescript',\n  collectCoverageFrom: [\n    \"src/**/*.{vue,ts}\",\n    \"!**/node_modules/**\",\n    \"!**/*.d.ts\"\n  ],\n  coverageReporters: [\"text\", \"json\", \"html\"],\n  testMatch: [ \"**/__tests__/**/*.[jt]s?(x)\", \"**/?(*.)+(spec|test).[jt]s?(x)\" ],\n  coveragePathIgnorePatterns: [\n    \"/node_modules/\",\n    \"/src/main.ts\",\n    \"/src/App.vue\",\n    \"/src/development/\",\n  ]\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"@variantjs/vue\",\n  \"version\": \"0.0.22\",\n  \"description\": \"Vue VariantJS: Fully configurable Vue 3 components styled with TailwindCSS\",\n  \"files\": [\n    \"dist/**/*\",\n    \"src/**/*\"\n  ],\n  \"types\": \"./dist/index.d.ts\",\n  \"main\": \"./dist/index.umd.js\",\n  \"module\": \"./dist/index.es.js\",\n  \"exports\": {\n    \".\": {\n      \"import\": \"./dist/index.es.js\",\n      \"require\": \"./dist/index.umd.js\"\n    }\n  },\n  \"sideEffects\": false,\n  \"keywords\": [\n    \"tailwindcss\",\n    \"vue\",\n    \"vue-tailwind\",\n    \"variantjs\",\n    \"vue3\"\n  ],\n  \"author\": \"Alfonso Bribiesca <alfonso@vexilo.com>\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/variantjs/vue\"\n  },\n  \"license\": \"MIT\",\n  \"private\": false,\n  \"scripts\": {\n    \"build\": \"vue-tsc --noEmit && vite build\",\n    \"serve\": \"vite preview\",\n    \"test\": \"jest -t\",\n    \"test:watch\": \"jest --watch -t\",\n    \"lint\": \"eslint src --fix\",\n    \"release\": \"release-it\",\n    \"demo\": \"vite --config ./vite.demo.config.ts\",\n    \"demo:build\": \"vite build --config ./vite.demo.config.ts\",\n    \"demo:serve\": \"vite preview --config ./vite.demo.config.ts\"\n  },\n  \"devDependencies\": {\n    \"@popperjs/core\": \"^2.11.0\",\n    \"@rollup/plugin-typescript\": \"^8.3.0\",\n    \"@tailwindcss/forms\": \"^0.4.0\",\n    \"@testing-library/vue\": \"^6.4.2\",\n    \"@types/body-scroll-lock\": \"^3.1.0\",\n    \"@types/jest\": \"^27.0.3\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.8.0\",\n    \"@typescript-eslint/parser\": \"^5.8.0\",\n    \"@vitejs/plugin-vue\": \"^2.0.1\",\n    \"@vue/cli-plugin-unit-jest\": \"^5.0.0-rc.1\",\n    \"@vue/compiler-sfc\": \"^3.2.26\",\n    \"@vue/test-utils\": \"^2.0.0-rc.6\",\n    \"@vue/vue3-jest\": \"^27.0.0-alpha.4\",\n    \"autoprefixer\": \"^10.4.0\",\n    \"body-scroll-lock\": \"^4.0.0-beta.0\",\n    \"eslint\": \"^8.5.0\",\n    \"eslint-config-airbnb-typescript\": \"^16.1.0\",\n    \"eslint-config-prettier\": \"^8.3.0\",\n    \"eslint-plugin-import\": \"^2.25.3\",\n    \"eslint-plugin-tree-shaking\": \"^1.9.2\",\n    \"eslint-plugin-vue\": \"^8.2.0\",\n    \"jest\": \"^27.4.5\",\n    \"prettier\": \"^2.5.1\",\n    \"release-it\": \"^14.11.8\",\n    \"tailwindcss\": \"^3.0.7\",\n    \"ts-jest\": \"^27.1.2\",\n    \"ts-vue-plugin\": \"^0.1.3\",\n    \"typescript\": \"^4.5.4\",\n    \"vite\": \"^2.7.7\",\n    \"vue\": \"^3.2.6\",\n    \"vue-loader\": \"^16.7.0\",\n    \"vue-router\": \"4\",\n    \"vue-tsc\": \"^0.30.1\",\n    \"vue3-jest\": \"^27.0.0-alpha.1\"\n  },\n  \"peerDependencies\": {\n    \"@popperjs/core\": \"^2.11.0\",\n    \"body-scroll-lock\": \"^4.0.0-beta.0\",\n    \"vue\": \"^3.2.6\"\n  },\n  \"release-it\": {\n    \"hooks\": {\n      \"before:init\": [\n        \"yarn lint\",\n        \"yarn test\"\n      ],\n      \"after:bump\": \"yarn build\"\n    }\n  },\n  \"dependencies\": {\n    \"@variantjs/core\": \"^0.0.79\"\n  }\n}\n"
  },
  {
    "path": "postcss.config.js",
    "content": "module.exports = {\n  plugins: {\n    tailwindcss: {},\n    autoprefixer: {},\n  },\n}\n"
  },
  {
    "path": "src/__tests/components/TAlert.spec.ts",
    "content": "import { mount } from '@vue/test-utils';\nimport TAlert from '@/components/TAlert.vue';\nimport { scopedParamsAsString, parseScopedParams } from '../testUtils';\n\ndescribe('TAlert.vue', () => {\n  it('renders the component without errors', () => {\n    const wrapper = mount(TAlert, {\n      slots: {\n        default: 'Hello World!',\n      },\n    });\n\n    expect(wrapper.vm.$el.textContent).toEqual('Hello World!');\n    expect(wrapper.vm.$refs.wrapper).toBeTruthy();\n    expect(wrapper.vm.$refs.body).toBeTruthy();\n    expect(wrapper.vm.$refs.close).toBeTruthy();\n    expect(wrapper.vm.$refs.closeIcon).toBeTruthy();\n  });\n\n  it('renders the `text` prop on the alert body', () => {\n    const wrapper = mount(TAlert, {\n      props: {\n        text: 'Hello World!',\n      },\n    });\n\n    expect(wrapper.vm.$el.textContent).toEqual('Hello World!');\n  });\n\n  it('prioritized the slot over the `text` prop', () => {\n    const wrapper = mount(TAlert, {\n      props: {\n        text: 'Goodbye World!',\n      },\n      slots: {\n        default: 'Hello World!',\n      },\n    });\n\n    expect(wrapper.vm.$el.textContent).toEqual('Hello World!');\n  });\n\n  it('accepts a custom `tagName` for the alert wrapper', () => {\n    const wrapper = mount(TAlert, {\n      props: {\n        tagName: 'fieldset',\n      },\n    });\n\n    expect(wrapper.vm.$refs.wrapper.tagName).toBe('FIELDSET');\n  });\n\n  it('accepts a custom `bodyTagName` for the alert wrapper', () => {\n    const wrapper = mount(TAlert, {\n      props: {\n        bodyTagName: 'fieldset',\n      },\n    });\n\n    expect(wrapper.vm.$refs.body.tagName).toBe('FIELDSET');\n  });\n\n  it('hides the closeButton if `dismissible` is set to `false`', () => {\n    const wrapper = mount(TAlert, {\n      props: {\n        dismissible: false,\n      },\n    });\n\n    expect(wrapper.vm.$refs.close).toBeUndefined();\n  });\n\n  it('hides the component when the close button is pressed ', async () => {\n    const wrapper = mount(TAlert);\n\n    const trigger = wrapper.get('button');\n\n    await trigger.trigger('click');\n\n    expect(wrapper.vm.shown).toBe(false);\n  });\n\n  it('starts with the alert hidden if `show` if set to `false`', () => {\n    const wrapper = mount(TAlert, {\n      props: {\n        show: false,\n      },\n    });\n\n    expect(wrapper.vm.shown).toBe(false);\n  });\n\n  it('emits `update:show` when show property is updated', async () => {\n    const wrapper = mount(TAlert);\n\n    wrapper.vm.doHide();\n\n    await wrapper.vm.$nextTick();\n\n    // assert event has been emitted\n    expect(wrapper.emitted()['update:show']).toBeTruthy();\n\n    // assert event payload\n    expect(wrapper.emitted()['update:show']).toEqual([[false]]);\n\n    wrapper.vm.doShow();\n\n    await wrapper.vm.$nextTick();\n\n    // assert event has been emitted\n    expect(wrapper.emitted()['update:show']).toBeTruthy();\n\n    // assert event payload\n    expect(wrapper.emitted()['update:show']).toEqual([[false], [true]]);\n  });\n\n  it('hides the element after the `timeout`', async () => {\n    jest.useFakeTimers();\n\n    const wrapper = mount(TAlert, {\n      props: {\n        timeout: 500,\n      },\n    });\n\n    jest.advanceTimersByTime(499);\n\n    expect(wrapper.vm.shown).toBe(true);\n\n    jest.advanceTimersByTime(1);\n\n    expect(wrapper.vm.shown).toBe(false);\n\n    jest.useRealTimers();\n  });\n\n  it('doesnt clear the timeout if not defined', async () => {\n    jest.useFakeTimers();\n\n    const timeoutSpy = jest.spyOn(window, 'setTimeout');\n    const clearTimeoutSpy = jest.spyOn(window, 'clearTimeout');\n\n    const wrapper = mount(TAlert);\n\n    wrapper.unmount();\n\n    expect(timeoutSpy).not.toHaveBeenCalled();\n    expect(clearTimeoutSpy).not.toHaveBeenCalled();\n\n    clearTimeoutSpy.mockRestore();\n    timeoutSpy.mockRestore();\n  });\n\n  it('clears the `timeout` when the element is unmounted', async () => {\n    jest.useFakeTimers();\n\n    const wrapper = mount(TAlert, {\n      props: {\n        timeout: 500,\n      },\n    });\n\n    const hideAction = jest.spyOn(wrapper.vm, 'doHide');\n\n    jest.advanceTimersByTime(499);\n\n    wrapper.unmount();\n\n    jest.advanceTimersByTime(1);\n\n    expect(hideAction).not.toHaveBeenCalled();\n\n    jest.useRealTimers();\n  });\n\n  it('clears the `timeout` when the element is hidden manually', async () => {\n    const clearTimeoutSpy = jest.spyOn(window, 'clearTimeout');\n\n    const wrapper = mount(TAlert, {\n      props: {\n        timeout: 500,\n      },\n    });\n\n    wrapper.vm.doHide();\n\n    expect(clearTimeoutSpy).toHaveBeenCalled();\n\n    clearTimeoutSpy.mockRestore();\n  });\n\n  it('accepts a custom `closeIcon``\u001b', async () => {\n    const closeIcon = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n    <path fill-rule=\"evenodd\" d=\"M12.707\" clip-rule=\"evenodd\"></path>\n  </svg>`;\n    const wrapper = mount(TAlert, {\n      props: {\n        closeIcon,\n      },\n    });\n\n    expect(wrapper.vm.$refs.close.innerHTML).toContain('<path fill-rule=\"evenodd\" d=\"M12.707\" clip-rule=\"evenodd\"');\n  });\n\n  it('has a closeButton slot\u001b', async () => {\n    // Supress \"Property undefined was accessed during render but is not defined on instance.\" warning\n    // @TODO consider an alternative to this\n    jest.spyOn(console, 'warn').mockImplementation(() => {});\n\n    const closeButton = '<button><span>x</span></button>';\n\n    const wrapper = mount(TAlert, {\n      slots: {\n        closeButton,\n      },\n    });\n\n    expect(wrapper.html()).toContain(closeButton);\n  });\n\n  it('exposes the `toggle`, `show` and `hide` methods and the configuration to the closeButton slot ', () => {\n    const wrapper = mount(TAlert, {\n      slots: {\n        closeButton: (params) => scopedParamsAsString(params),\n      },\n    });\n\n    const scopeParamKeys = parseScopedParams(wrapper.text());\n\n    expect(scopeParamKeys).toEqual({\n      show: 'function',\n      hide: 'function',\n      toggle: 'function',\n      configuration: 'object',\n    });\n  });\n\n  it('exposes the `toggle`, `show` and `hide` methods and the configuration to the default slot ', () => {\n    const wrapper = mount(TAlert, {\n      slots: {\n        default: (params) => scopedParamsAsString(params),\n      },\n    });\n\n    const scopeParamKeys = parseScopedParams(wrapper.text());\n\n    expect(scopeParamKeys).toEqual({\n      show: 'function',\n      hide: 'function',\n      toggle: 'function',\n      configuration: 'object',\n    });\n  });\n\n  it('syncs the `shown` value with the prop configuration', async () => {\n    const wrapper = mount(TAlert);\n\n    await wrapper.setProps({\n      show: false,\n    });\n\n    expect(wrapper.vm.shown).toBe(false);\n\n    await wrapper.setProps({\n      show: true,\n    });\n\n    expect(wrapper.vm.shown).toBe(true);\n  });\n\n  it('hides or shows the component with the doToggle method', () => {\n    const wrapper = mount(TAlert);\n\n    wrapper.vm.doToggle();\n\n    expect(wrapper.vm.shown).toBe(false);\n\n    wrapper.vm.doToggle();\n\n    expect(wrapper.vm.shown).toBe(true);\n  });\n});\n"
  },
  {
    "path": "src/__tests/components/TButton.spec.ts",
    "content": "/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/no-non-null-assertion */\n\nimport { shallowMount } from '@vue/test-utils';\nimport { TButtonConfig } from '@variantjs/core';\nimport TButton from '../../components/TButton.vue';\n\ndescribe('TButton.vue', () => {\n  it('renders the button', () => {\n    const wrapper = shallowMount(TButton);\n    expect(wrapper.get('button')).toBeTruthy();\n  });\n\n  it('renders the button with a default set of classes', () => {\n    const wrapper = shallowMount(TButton);\n\n    expect(wrapper.html()).toBe(`<button class=\"${TButtonConfig.classes}\"></button>`);\n  });\n\n  it('renders the button without attributes if no default theme', () => {\n    const wrapper = shallowMount(TButton, {\n      global: {\n        provide: {\n          configuration: {\n            TButton: {\n              classes: undefined,\n            },\n          },\n        },\n      },\n    });\n\n    expect(wrapper.html()).toBe('<button></button>');\n  });\n\n  it('renders the button with the text in the slot', () => {\n    const wrapper = shallowMount(TButton, {\n      props: {\n        classes: undefined,\n      },\n      slots: {\n        default: 'Press me!',\n      },\n    });\n\n    expect(wrapper.html()).toBe('<button>Press me!</button>');\n  });\n\n  it('set the props.value as the button value', () => {\n    const value = 'button value';\n    const wrapper = shallowMount(TButton, {\n      props: { value },\n    });\n\n    expect(wrapper.vm.$el.value).toBe(value);\n  });\n\n  it('doesnt add the tagName as attribute', () => {\n    const wrapper = shallowMount(TButton, {\n      props: { tagName: 'a' },\n    });\n\n    expect(wrapper.vm.$el.attributes.tagName).toBeUndefined();\n  });\n\n  it('disables the button', async () => {\n    const wrapper = shallowMount(TButton, {\n      props: { disabled: false },\n    });\n    expect(wrapper.vm.$el.disabled).toBe(false);\n\n    await wrapper.setProps({ disabled: true });\n\n    expect(wrapper.vm.$el.disabled).toBe(true);\n  });\n\n  it('adds the configuration attribute', async () => {\n    const wrapper = shallowMount(TButton, {\n      global: {\n        provide: {\n          configuration: {\n            TButton: {\n              type: 'button',\n              'data-id': 'something',\n            },\n          },\n        },\n      },\n    });\n\n    const button = wrapper.vm.$el as HTMLButtonElement;\n    expect(button.type).toBe('button');\n    expect(button.dataset.id).toBe('something');\n  });\n\n  it('prioritizes the attribute over the configuratiion', async () => {\n    const wrapper = shallowMount(TButton, {\n      global: {\n        provide: {\n          configuration: {\n            TButton: {\n              type: 'button',\n            },\n          },\n        },\n      },\n      attrs: {\n        type: 'submit',\n      },\n    });\n\n    const button = wrapper.vm.$el;\n    expect(button.type).toBe('submit');\n  });\n\n  it('accepts misc button attributes', async () => {\n    const wrapper = shallowMount(TButton);\n\n    const values = {\n      id: {\n        default: '',\n        new: 'new-id',\n      },\n      autofocus: {\n        default: false,\n        new: true,\n      },\n      disabled: {\n        default: false,\n        new: true,\n      },\n      name: {\n        default: '',\n        new: 'new-name',\n      },\n      title: {\n        default: '',\n        new: 'new-title',\n      },\n      type: {\n        default: 'submit',\n        new: 'button',\n      },\n    };\n\n    const newProps: any = {};\n    // Check for the default values\n    Object.keys(values).forEach((key) => {\n      const elementValue = (values as any)[key];\n      expect(wrapper.vm.$el[elementValue.keyName || key]).toBe(elementValue.default);\n\n      newProps[key as any] = elementValue.new;\n    });\n\n    await wrapper.setProps(newProps);\n\n    // Check for the new values\n    Object.keys(values).forEach((key) => {\n      const elementValue = (values as any)[key];\n      expect(wrapper.vm.$el[elementValue.keyName || key]).toBe(elementValue.new);\n    });\n  });\n\n  it('emits native button events', () => {\n    const onClick = jest.fn();\n    const onBlur = jest.fn();\n    const onFocus = jest.fn();\n    const onKeyup = jest.fn();\n\n    const wrapper = shallowMount(TButton, {\n      attrs: {\n        onClick,\n        onBlur,\n        onFocus,\n        onKeyup,\n      },\n    });\n\n    const button = wrapper.vm.$el;\n\n    button.dispatchEvent(new MouseEvent('click'));\n    expect(onClick).toHaveBeenCalled();\n\n    button.dispatchEvent(new FocusEvent('focus'));\n    expect(onFocus).toHaveBeenCalled();\n\n    button.dispatchEvent(new FocusEvent('blur'));\n    expect(onBlur).toHaveBeenCalled();\n\n    button.dispatchEvent(new KeyboardEvent('keyup', { key: 'a' }));\n    expect(onKeyup).toHaveBeenCalled();\n  });\n\n  it('has native button methods', () => {\n    const wrapper = shallowMount(TButton);\n\n    const button = wrapper.vm.$el;\n\n    expect(typeof button.click).toBe('function');\n    expect(typeof button.focus).toBe('function');\n    expect(typeof button.blur).toBe('function');\n  });\n\n  it('triggers custom events', async () => {\n    const onCustom = jest.fn();\n\n    const wrapper = shallowMount(TButton, {\n      attrs: {\n        onCustom,\n      },\n    });\n    const button = wrapper.vm.$el as HTMLButtonElement;\n\n    const evt = new CustomEvent('custom', { detail: 'my-custom-event' });\n    button.dispatchEvent(evt);\n\n    expect(onCustom).toHaveBeenCalled();\n  });\n\n  it('default to button tag', () => {\n    const wrapper = shallowMount(TButton);\n\n    expect(wrapper.vm.$el.tagName).toBe('BUTTON');\n  });\n\n  it('accepts anchor tag', () => {\n    const wrapper = shallowMount(TButton, {\n      props: { tagName: 'a' },\n    });\n\n    expect(wrapper.vm.$el.tagName).toBe('A');\n  });\n\n  it('uses anchor tag when has href attribute', () => {\n    const wrapper = shallowMount(TButton, {\n      props: { href: 'https://www.vexilo.com/' },\n    });\n\n    expect(wrapper.vm.$el.tagName).toBe('A');\n    expect(wrapper.vm.$el.href).toBe('https://www.vexilo.com/');\n  });\n\n  describe('Router Link', () => {\n    it('has router link related props', () => {\n      const props = {\n        to: '/something',\n        replace: true,\n        activeClass: 'activeClass',\n        exactActiveClass: 'exactActiveClass',\n        custom: true,\n        ariaCurrentValue: 'location',\n      };\n\n      type RouterProps = typeof props;\n\n      const wrapper = shallowMount(TButton, {\n        props: props as any,\n      });\n\n      Object.keys(props).forEach((key) => {\n        expect((wrapper.vm as any)[key]).toBe(props[key as keyof RouterProps]);\n      });\n    });\n\n    it('doesnt have a router link component by default', () => {\n      const wrapper = shallowMount(TButton);\n      expect(wrapper.vm.routerLinkComponentAvailable).toBe(false);\n    });\n\n    it('can determine when a router link component is available', () => {\n      const RouterLink = {\n        name: 'RouterLink',\n        template: '',\n      };\n\n      const wrapper = shallowMount(TButton, {\n        global: {\n          components: {\n            RouterLink,\n          },\n        },\n      });\n\n      expect(wrapper.vm.routerLinkComponentAvailable).toBe(true);\n    });\n\n    it('determine that a router link component is available if has a NuxtLink', () => {\n      const NuxtLink = {\n        name: 'NuxtLink',\n        template: '',\n      };\n\n      const wrapper = shallowMount(TButton, {\n        global: {\n          components: {\n            NuxtLink,\n          },\n        },\n      });\n\n      (wrapper.vm.$options.components as any).NuxtLink = {};\n      expect(wrapper.vm.routerLinkComponentAvailable).toBe(true);\n    });\n\n    it('uses a router-link when `to` prop is defined and the route link component is available', () => {\n      const RouterLink = {\n        name: 'RouterLink',\n        template: '',\n      };\n\n      const wrapper = shallowMount(TButton, {\n        global: {\n          components: {\n            RouterLink,\n          },\n        },\n        props: {\n          to: '/some-place',\n          classes: undefined,\n        },\n      });\n\n      expect(wrapper.vm.useRouterLink).toBe(true);\n      expect(wrapper.getComponent(RouterLink)).toBeTruthy();\n    });\n\n    it('doesnt use a router-link when `to` prop is not defined even if route link component is available', () => {\n      const RouterLink = {\n        name: 'RouterLink',\n        template: '',\n      };\n\n      const wrapper = shallowMount(TButton, {\n        global: {\n          components: {\n            RouterLink,\n          },\n        },\n      });\n\n      expect(wrapper.vm.useRouterLink).toBe(false);\n    });\n\n    it('uses a nuxt-link when `to` prop is defined and the nuxt-link component is available', () => {\n      const NuxtLink = {\n        name: 'NuxtLink',\n        template: '',\n      };\n\n      const wrapper = shallowMount(TButton, {\n        global: {\n          components: {\n            NuxtLink,\n          },\n        },\n        props: {\n          to: '/some-place',\n          classes: undefined,\n        },\n      });\n\n      expect(wrapper.vm.useRouterLink).toBe(true);\n      expect(wrapper.getComponent(NuxtLink)).toBeTruthy();\n    });\n\n    it('adds the routerLink related prop', () => {\n      const props: any = {\n        to: '/something',\n        replace: true,\n        activeClass: 'activeClass',\n        exactActiveClass: 'exactActiveClass',\n        custom: true,\n        ariaCurrentValue: 'location',\n      };\n\n      const RouterLink = {\n        name: 'RouterLink',\n        template: '',\n        props: Object.keys(props),\n      };\n\n      const wrapper = shallowMount(TButton, {\n        global: {\n          components: {\n            RouterLink,\n          },\n        },\n        props: {\n          ...props,\n          href: '/something',\n        },\n      });\n\n      const component = wrapper.getComponent(RouterLink);\n      expect(component.props()).toEqual(props);\n    });\n  });\n});\n"
  },
  {
    "path": "src/__tests/components/TCard.spec.ts",
    "content": "import { shallowMount } from '@vue/test-utils';\nimport { TCardConfig } from '@variantjs/core';\nimport TCard from '@/components/TCard.vue';\n\ndescribe('TCard.vue', () => {\n  it('renders the component without errors', () => {\n    const wrapper = shallowMount(TCard);\n    expect(wrapper.vm.$el.tagName).toBe('DIV');\n  });\n\n  it('accepts a different tag for the wrapper', () => {\n    const wrapper = shallowMount(TCard, {\n      props: {\n        tagName: 'table',\n      },\n    });\n    expect(wrapper.vm.$el.tagName).toBe('TABLE');\n  });\n\n  it('renders the default slot content', () => {\n    const wrapper = shallowMount(TCard, {\n      slots: {\n        default: 'Im a card!',\n      },\n    });\n\n    expect(wrapper.vm.$el.querySelector('div').innerHTML).toBe('Im a card!');\n  });\n\n  it('doesnt have title or footer by default', () => {\n    const wrapper = shallowMount(TCard, {\n      slots: {\n        default: 'Im a card!',\n      },\n    });\n\n    expect(wrapper.vm.$el.querySelectorAll('div').length).toBe(1);\n  });\n\n  it('adds the header slot', () => {\n    const wrapper = shallowMount(TCard, {\n      slots: {\n        header: 'Im a header!',\n        default: 'Im a card!',\n      },\n    });\n\n    expect(wrapper.vm.$el.querySelectorAll('div').length).toBe(2);\n    expect(wrapper.vm.$el.querySelectorAll('div')[0].innerHTML).toBe('Im a header!');\n  });\n\n  it('adds the footer slot', () => {\n    const wrapper = shallowMount(TCard, {\n      slots: {\n        default: 'Im a card!',\n        footer: 'Im a footer!',\n      },\n    });\n\n    expect(wrapper.vm.$el.querySelectorAll('div').length).toBe(2);\n    expect(wrapper.vm.$el.querySelectorAll('div')[1].innerHTML).toBe('Im a footer!');\n  });\n\n  it('adds the header prop', () => {\n    const wrapper = shallowMount(TCard, {\n      props: {\n        header: 'Im a header!',\n      },\n      slots: {\n        default: 'Im a card!',\n      },\n    });\n\n    expect(wrapper.vm.$el.querySelectorAll('div').length).toBe(2);\n    expect(wrapper.vm.$el.querySelectorAll('div')[0].innerHTML).toBe('Im a header!');\n  });\n\n  it('adds the footer prop', () => {\n    const wrapper = shallowMount(TCard, {\n      props: {\n        footer: 'Im a footer!',\n      },\n      slots: {\n        default: 'Im a card!',\n      },\n\n    });\n\n    expect(wrapper.vm.$el.querySelectorAll('div').length).toBe(2);\n    expect(wrapper.vm.$el.querySelectorAll('div')[1].innerHTML).toBe('Im a footer!');\n  });\n\n  it('adds the body prop', () => {\n    const wrapper = shallowMount(TCard, {\n      props: {\n        body: 'Im a card!',\n      },\n    });\n\n    expect(wrapper.vm.$el.querySelectorAll('div').length).toBe(1);\n    expect(wrapper.vm.$el.querySelector('div').innerHTML).toBe('Im a card!');\n  });\n\n  it('prioritizes slots over props', () => {\n    const wrapper = shallowMount(TCard, {\n      props: {\n        header: 'Im a header!',\n        body: 'Im a card!',\n        footer: 'Im a footer!',\n      },\n      slots: {\n        default: 'default slot',\n        header: 'header slot',\n        footer: 'footer slot',\n      },\n    });\n\n    const els = wrapper.vm.$el.querySelectorAll('div');\n    expect(els.length).toBe(3);\n    expect(els[0].innerHTML).toBe('header slot');\n    expect(els[1].innerHTML).toBe('default slot');\n    expect(els[2].innerHTML).toBe('footer slot');\n  });\n\n  it('has a default theme', () => {\n    const wrapper = shallowMount(TCard, {\n      slots: {\n        default: 'default slot',\n        header: 'header slot',\n        footer: 'footer slot',\n      },\n    });\n\n    const wrap = wrapper.vm.$el as HTMLDivElement;\n    const els = wrapper.vm.$el.querySelectorAll('div');\n    const header = els[0];\n    const body = els[1];\n    const footer = els[2];\n\n    expect(wrap.className).toBe(TCardConfig.classes.wrapper);\n    expect(header.className).toBe(TCardConfig.classes.header);\n    expect(body.className).toBe(TCardConfig.classes.body);\n    expect(footer.className).toBe(TCardConfig.classes.footer);\n  });\n\n  it('adds html attributes', () => {\n    const wrapper = shallowMount(TCard, {\n      attrs: {\n        id: 'my-id',\n      },\n    });\n\n    const wrap = wrapper.vm.$el as HTMLDivElement;\n\n    expect(wrap.getAttribute('id')).toBe('my-id');\n  });\n\n  it('adds attributes from global configuration', () => {\n    const wrapper = shallowMount(TCard, {\n      global: {\n        provide: {\n          configuration: {\n            TCard: {\n              id: 'my-id',\n            },\n          },\n        },\n      },\n    });\n\n    const wrap = wrapper.vm.$el as HTMLDivElement;\n\n    expect(wrap.getAttribute('id')).toBe('my-id');\n  });\n\n  it('used the props from global configuration', () => {\n    const wrapper = shallowMount(TCard, {\n      global: {\n        provide: {\n          configuration: {\n            TCard: {\n              tagName: 'table',\n              footer: 'Copyright @alfonsobires',\n            },\n          },\n        },\n      },\n    });\n\n    expect(wrapper.vm.$el.tagName).toBe('TABLE');\n    expect(wrapper.vm.$el.querySelector('div').innerHTML).toBe('Copyright @alfonsobires');\n  });\n});\n"
  },
  {
    "path": "src/__tests/components/TCheckbox.integration.spec.ts",
    "content": "/* eslint-disable @typescript-eslint/no-non-null-assertion */\nimport { render, fireEvent } from '@testing-library/vue';\nimport TCheckbox from '@/components/TCheckbox.vue';\n\ndescribe('TCheckbox.vue', () => {\n  it('handles the v-model', async () => {\n    const modelValue = ['A'];\n    const { container } = render(TCheckbox, {\n      props: {\n        modelValue,\n      },\n      attrs: {\n        name: 'checkbox-input',\n        value: 'A',\n      },\n    });\n    const { container: container2 } = render(TCheckbox, {\n      props: {\n        modelValue,\n      },\n      attrs: {\n        name: 'checkbox-input',\n        value: 'B',\n      },\n    });\n\n    const input = container.querySelector('input')!;\n    const input2 = container2.querySelector('input')!;\n\n    expect(input.checked).toBe(true);\n    expect(input2.checked).toBe(false);\n\n    await fireEvent.click(input2!);\n\n    expect(input.checked).toBe(true);\n    expect(input2.checked).toBe(true);\n\n    await fireEvent.click(input!);\n\n    expect(input.checked).toBe(false);\n    expect(input2.checked).toBe(true);\n  });\n\n  it('handles the v-model with not regular value types', async () => {\n    const modelValue = [[123, 'A']];\n    const { container } = render(TCheckbox, {\n      props: {\n        modelValue,\n      },\n      attrs: {\n        name: 'checkbox-input',\n        value: [123, 'A'],\n      },\n    });\n    const { container: container2 } = render(TCheckbox, {\n      props: {\n        modelValue,\n      },\n      attrs: {\n        name: 'checkbox-input',\n        value: () => {},\n      },\n    });\n    const { container: container3 } = render(TCheckbox, {\n      props: {\n        modelValue,\n      },\n      attrs: {\n        name: 'checkbox-input',\n        value: { A: 'B' },\n      },\n    });\n\n    const input = container.querySelector('input')!;\n    const input2 = container2.querySelector('input')!;\n    const input3 = container3.querySelector('input')!;\n\n    expect(input.checked).toBe(true);\n    expect(input2.checked).toBe(false);\n    expect(input3.checked).toBe(false);\n\n    await fireEvent.click(input2!);\n\n    expect(input.checked).toBe(true);\n    expect(input2.checked).toBe(true);\n    expect(input3.checked).toBe(false);\n\n    await fireEvent.click(input3!);\n\n    expect(input.checked).toBe(true);\n    expect(input2.checked).toBe(true);\n    expect(input3.checked).toBe(true);\n  });\n});\n"
  },
  {
    "path": "src/__tests/components/TCheckbox.spec.ts",
    "content": "/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/no-non-null-assertion */\nimport { shallowMount } from '@vue/test-utils';\nimport { TCheckboxConfig } from '@variantjs/core';\nimport TCheckbox from '@/components/TCheckbox.vue';\n\ndescribe('TCheckbox.vue', () => {\n  it('renders the input', () => {\n    const wrapper = shallowMount(TCheckbox);\n    expect(wrapper.get('input')).toBeTruthy();\n  });\n\n  it('renders the radio input with a default set of classes', () => {\n    const wrapper = shallowMount(TCheckbox);\n\n    expect(wrapper.html()).toBe(`<input type=\"checkbox\" class=\"${TCheckboxConfig.classes}\">`);\n  });\n\n  it('renders the input without attributes if no default theme', () => {\n    const wrapper = shallowMount(TCheckbox, {\n      global: {\n        provide: {\n          configuration: {\n            TCheckbox: {\n              classes: undefined,\n            },\n          },\n        },\n      },\n    });\n\n    expect(wrapper.html()).toBe('<input type=\"checkbox\">');\n  });\n\n  it('adds the value attribute', () => {\n    const value = 'input value';\n    const wrapper = shallowMount(TCheckbox, {\n      attrs: { value },\n    });\n\n    expect(wrapper.vm.$el.value).toBe(value);\n  });\n\n  it('doesnt add the modelValue as attribute', () => {\n    const value = ['input value'];\n    const wrapper = shallowMount(TCheckbox, {\n      props: { modelValue: value },\n      attrs: { value },\n    });\n\n    expect(wrapper.vm.$el.attributes.modelValue).toBeUndefined();\n  });\n\n  it('set as checked if model value contains the value ', async () => {\n    const value = 'input value';\n    const wrapper = shallowMount(TCheckbox, {\n      props: { modelValue: ['something else'] },\n      attrs: { value },\n    });\n\n    const radio = wrapper.vm.$el as HTMLInputElement;\n    expect(radio.value).toBe(value);\n    expect(radio.checked).toBe(false);\n\n    await wrapper.setProps({\n      modelValue: [value, 'something else'],\n    });\n\n    expect(radio.value).toBe(value);\n    expect(radio.checked).toBe(true);\n  });\n\n  it('disables the input', async () => {\n    const wrapper = shallowMount(TCheckbox, {\n      props: { disabled: false },\n    });\n    expect(wrapper.vm.$el.disabled).toBe(false);\n\n    await wrapper.setProps({ disabled: true });\n\n    expect(wrapper.vm.$el.disabled).toBe(true);\n  });\n\n  it('accepts misc input attributes', async () => {\n    const wrapper = shallowMount(TCheckbox);\n\n    const values = {\n      id: {\n        default: '',\n        new: 'new-id',\n      },\n      autocomplete: {\n        default: '',\n        new: 'on',\n      },\n      autofocus: {\n        default: false,\n        new: true,\n      },\n      disabled: {\n        default: false,\n        new: true,\n      },\n      max: {\n        default: '',\n        new: '10',\n      },\n      maxlength: {\n        keyName: 'maxLength',\n        default: 524288,\n        new: 12,\n      },\n      minlength: {\n        keyName: 'minLength',\n        default: 0,\n        new: 2,\n      },\n      min: {\n        default: '',\n        new: '3',\n      },\n      multiple: {\n        default: false,\n        new: true,\n      },\n      name: {\n        default: '',\n        new: 'new-name',\n      },\n      pattern: {\n        default: '',\n        new: '[A-Za-z]{3}',\n      },\n      placeholder: {\n        default: '',\n        new: 'new placeholder',\n      },\n      readonly: {\n        keyName: 'readOnly',\n        default: false,\n        new: true,\n      },\n      required: {\n        default: false,\n        new: true,\n      },\n    };\n\n    const netProps: any = {};\n    // Check for the default values\n    Object.keys(values).forEach((key) => {\n      const elementValue = (values as any)[key];\n      expect(wrapper.vm.$el[elementValue.keyName || key]).toBe(elementValue.default);\n\n      netProps[key as any] = elementValue.new;\n    });\n\n    await wrapper.setProps(netProps);\n\n    // Check for the new values\n    Object.keys(values).forEach((key) => {\n      const elementValue = (values as any)[key];\n      expect(wrapper.vm.$el[elementValue.keyName || key]).toBe(elementValue.new);\n    });\n  });\n\n  it('emits an update event with the input value', () => {\n    const modelValue = 'original value';\n\n    const wrapper = shallowMount(TCheckbox, {\n      props: {\n        modelValue,\n      },\n    });\n\n    const inputValue = 'new value';\n\n    wrapper.setValue(inputValue);\n\n    expect(wrapper.emitted('update:modelValue')).toBeTruthy();\n\n    // assert event count\n    expect(wrapper.emitted('update:modelValue')?.length).toBe(1);\n\n    // assert event payload\n    expect(wrapper.emitted('update:modelValue')![0]).toEqual([inputValue]);\n  });\n\n  it('emits native input events', () => {\n    const onChange = jest.fn();\n    const onBlur = jest.fn();\n    const onFocus = jest.fn();\n    const onKeyup = jest.fn();\n    const onInput = jest.fn();\n\n    const wrapper = shallowMount(TCheckbox, {\n      attrs: {\n        onChange,\n        onBlur,\n        onFocus,\n        onKeyup,\n        onInput,\n      },\n    });\n\n    const input = wrapper.vm.$el;\n\n    input.dispatchEvent(new Event('change'));\n    expect(onChange).toHaveBeenCalled();\n\n    input.dispatchEvent(new FocusEvent('focus'));\n    expect(onFocus).toHaveBeenCalled();\n\n    input.dispatchEvent(new FocusEvent('blur'));\n    expect(onBlur).toHaveBeenCalled();\n\n    input.dispatchEvent(new InputEvent('input'));\n    expect(onInput).toHaveBeenCalled();\n\n    input.dispatchEvent(new KeyboardEvent('keyup', { key: 'a' }));\n    expect(onKeyup).toHaveBeenCalled();\n  });\n\n  it('has native input methods', () => {\n    const wrapper = shallowMount(TCheckbox);\n\n    const input = wrapper.vm.$el;\n\n    expect(typeof input.click).toBe('function');\n    expect(typeof input.focus).toBe('function');\n  });\n\n  it('triggers custom events', async () => {\n    const onCustom = jest.fn();\n\n    const wrapper = shallowMount(TCheckbox, {\n      attrs: {\n        onCustom,\n      },\n    });\n    const input = wrapper.vm.$el as HTMLInputElement;\n\n    const evt = new CustomEvent('custom', { detail: 'my-custom-event' });\n    input.dispatchEvent(evt);\n\n    expect(onCustom).toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "src/__tests/components/TDialog.spec.ts",
    "content": "/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { mount } from '@vue/test-utils';\nimport { h } from 'vue';\nimport { DialogHideReason, DialogType } from '@variantjs/core';\nimport TDialog from '@/components/TDialog.vue';\nimport { Emitter } from '../../utils/emitter';\nimport plugin from '../../plugin';\n// eslint-disable-next-line no-async-promise-executor\nconst waitUntilModalIsShown = (wrapper: any): Promise<void> => new Promise(async (resolve) => {\n  do {\n    // eslint-disable-next-line no-await-in-loop\n    await wrapper.vm.$nextTick();\n  } while (wrapper.vm.$refs.modalRef.showModal === false);\n  await wrapper.vm.$nextTick();\n\n  resolve();\n});\n\n// eslint-disable-next-line no-async-promise-executor\nconst waitUntilModalIsHidden = (wrapper: any): Promise<void> => new Promise(async (resolve) => {\n  do {\n    // eslint-disable-next-line no-await-in-loop\n    await wrapper.vm.$nextTick();\n  } while (wrapper.vm.$refs.modalRef.showComponent === true);\n  await wrapper.vm.$nextTick();\n\n  resolve();\n});\n\ndescribe('TDialog.vue', () => {\n  beforeEach(() => {\n    TDialog.props.teleport.default = false;\n    TDialog.props.modelValue.default = true;\n  });\n\n  afterEach(() => {\n    TDialog.props.teleport.default = true;\n    TDialog.props.modelValue.default = false;\n  });\n\n  it('mount the component without errors', async () => {\n    const wrapper = mount(TDialog);\n\n    expect(wrapper.get('div').attributes('tabindex')).toEqual('0');\n  });\n\n  describe('Props passed to the modal', () => {\n    it('passes the dialogAttributes to the modalAttributes ', () => {\n      const dialogAttributes = {\n        'data-foo': 'bar',\n        class: 'bg-red-500',\n      };\n\n      const wrapper = mount(TDialog, {\n        props: {\n          dialogAttributes,\n        },\n      });\n\n      expect(wrapper.vm.$refs.modalRef.modalAttributes).toEqual(dialogAttributes);\n    });\n\n    it('passes the clickToClose setting ', () => {\n      const wrapper = mount(TDialog, {\n        props: {\n          clickToClose: false,\n        },\n      });\n\n      expect(wrapper.vm.$refs.modalRef.clickToClose).toBe(false);\n    });\n\n    it('passes the escToClose setting ', () => {\n      const wrapper = mount(TDialog, {\n        props: {\n          escToClose: false,\n        },\n      });\n\n      expect(wrapper.vm.$refs.modalRef.escToClose).toBe(false);\n    });\n\n    it('passes the disableBodyScroll setting ', () => {\n      const wrapper = mount(TDialog, {\n        props: {\n          disableBodyScroll: false,\n        },\n      });\n\n      expect(wrapper.vm.$refs.modalRef.disableBodyScroll).toBe(false);\n    });\n\n    it('passes the bodyScrollLockOptions setting ', () => {\n      const bodyScrollLockOptions = {\n        reserveScrollBarGap: true,\n      };\n      const wrapper = mount(TDialog, {\n        props: {\n          bodyScrollLockOptions,\n        },\n      });\n\n      expect(wrapper.vm.$refs.modalRef.bodyScrollLockOptions).toEqual(bodyScrollLockOptions);\n    });\n\n    it('passes the negative value of showCloseButton setting to the hideCloseButton ', () => {\n      const wrapper = mount(TDialog, {\n        props: {\n          showCloseButton: false,\n        },\n      });\n\n      expect(wrapper.vm.$refs.modalRef.hideCloseButton).toBe(true);\n    });\n\n    it('passes the teleport setting ', () => {\n      const wrapper = mount(TDialog, {\n        props: {\n          teleport: false,\n        },\n      });\n\n      expect(wrapper.vm.$refs.modalRef.teleport).toBe(false);\n    });\n\n    it('passes the teleportTo setting ', () => {\n      const div = document.createElement('div');\n      div.id = 'app';\n\n      document.body.append(div);\n\n      const wrapper = mount(TDialog, {\n        props: {\n          teleportTo: '#app',\n        },\n      });\n\n      expect(wrapper.vm.$refs.modalRef.teleportTo).toBe('#app');\n    });\n  });\n\n  describe('Title', () => {\n    it('adds the title', () => {\n      const wrapper = mount(TDialog, {\n        props: {\n          title: 'Are you sure?',\n        },\n      });\n\n      expect(wrapper.find('h3').text()).toEqual('Are you sure?');\n    });\n\n    it('adds the title trough the slot', () => {\n      const wrapper = mount(TDialog, {\n        slots: {\n          title: 'Are you sure?',\n        },\n      });\n\n      expect(wrapper.find('h3').text()).toEqual('Are you sure?');\n    });\n\n    it('accepts a title tag', () => {\n      const wrapper = mount(TDialog, {\n        props: {\n          title: 'Are you sure?',\n          titleTag: 'h1',\n        },\n      });\n\n      expect(wrapper.find('h1').text()).toEqual('Are you sure?');\n    });\n\n    it('doesnt add the title if not set', () => {\n      const wrapper = mount(TDialog);\n\n      expect(wrapper.find('h3').exists()).toBe(false);\n    });\n  });\n\n  describe('Text', () => {\n    it('adds the text', () => {\n      const wrapper = mount(TDialog, {\n        props: {\n          text: 'This action cannot be undone',\n        },\n      });\n\n      expect(wrapper.find('p').text()).toEqual('This action cannot be undone');\n    });\n\n    it('adds the text trough the slot', () => {\n      const wrapper = mount(TDialog, {\n        slots: {\n          text: 'This action cannot be undone',\n        },\n      });\n\n      expect(wrapper.find('p').text()).toEqual('This action cannot be undone');\n    });\n\n    it('accepts a text tag', () => {\n      const wrapper = mount(TDialog, {\n        props: {\n          text: 'This action cannot be undone',\n          textTag: 'blockquote',\n        },\n      });\n\n      expect(wrapper.find('blockquote').text()).toEqual('This action cannot be undone');\n    });\n\n    it('doesnt add the text if not set', () => {\n      const wrapper = mount(TDialog);\n\n      expect(wrapper.find('p').exists()).toBe(false);\n    });\n  });\n\n  describe('Cancel Button', () => {\n    const props = {\n      type: 'confirm',\n    };\n\n    it('has a default label', () => {\n      const wrapper = mount(TDialog, { props });\n\n      const cancelButton = wrapper.vm.$refs.cancelButton as HTMLButtonElement;\n\n      expect(cancelButton.textContent).toEqual('Cancel');\n    });\n\n    it('has a default aria-label attribute', () => {\n      const wrapper = mount(TDialog, { props });\n\n      const cancelButton = wrapper.vm.$refs.cancelButton as HTMLButtonElement;\n\n      expect(cancelButton.getAttribute('aria-label')).toEqual('Cancel');\n    });\n\n    it('accepts a different label and aria-label', () => {\n      const wrapper = mount(TDialog, {\n        props: {\n          ...props,\n          cancelButtonText: 'Nah',\n          cancelButtonAriaLabel: 'Nah Button',\n        },\n      });\n\n      const cancelButton = wrapper.vm.$refs.cancelButton as HTMLButtonElement;\n\n      expect(cancelButton.textContent).toEqual('Nah');\n      expect(cancelButton.getAttribute('aria-label')).toEqual('Nah Button');\n    });\n\n    it('calls the cancel method when clicked', () => {\n      const wrapper = mount(TDialog, { props });\n\n      const cancelFnMock = jest.fn();\n\n      wrapper.vm.cancel = cancelFnMock;\n\n      const cancelButton = wrapper.vm.$refs.cancelButton as HTMLButtonElement;\n\n      cancelButton.dispatchEvent(new Event('click'));\n\n      expect(cancelFnMock).toHaveBeenCalled();\n    });\n\n    it('closes the modal when cancel button is clicked', async () => {\n      const wrapper = mount(TDialog, { props });\n\n      wrapper.vm.cancel();\n\n      await waitUntilModalIsHidden(wrapper);\n\n      expect(wrapper.emitted()).toHaveProperty('hidden');\n      expect(wrapper.emitted('hidden')).toEqual([[{\n        hideReason: 'cancel',\n        isCancel: true,\n        isDismissed: false,\n        isOk: false,\n      }]]);\n    });\n  });\n\n  describe('OK Button', () => {\n    const props = {\n      type: 'confirm',\n    };\n\n    it('has a default label', () => {\n      const wrapper = mount(TDialog, { props });\n\n      const okButton = wrapper.vm.$refs.okButton as HTMLButtonElement;\n\n      expect(okButton.textContent).toEqual('OK');\n    });\n\n    it('has a default aria-label attribute', () => {\n      const wrapper = mount(TDialog, { props });\n\n      const okButton = wrapper.vm.$refs.okButton as HTMLButtonElement;\n\n      expect(okButton.getAttribute('aria-label')).toEqual('OK');\n    });\n\n    it('accepts a different label and aria-label', () => {\n      const wrapper = mount(TDialog, {\n        props: {\n          ...props,\n          okButtonText: 'Yei!',\n          okButtonAriaLabel: 'Ok Button',\n        },\n      });\n\n      const okButton = wrapper.vm.$refs.okButton as HTMLButtonElement;\n\n      expect(okButton.textContent).toEqual('Yei!');\n      expect(okButton.getAttribute('aria-label')).toEqual('Ok Button');\n    });\n\n    it('calls the ok method when clicked', () => {\n      const wrapper = mount(TDialog, { props });\n\n      const okFnMock = jest.fn();\n\n      wrapper.vm.ok = okFnMock;\n\n      const okButton = wrapper.vm.$refs.okButton as HTMLButtonElement;\n\n      okButton.dispatchEvent(new Event('click'));\n\n      expect(okFnMock).toHaveBeenCalled();\n    });\n  });\n\n  describe('Dialog types', () => {\n    describe('Alert type', () => {\n      const props = {\n        type: 'alert',\n      };\n      it('has an ok button', () => {\n        const wrapper = mount(TDialog, { props });\n\n        const { okButton } = wrapper.vm.$refs;\n\n        expect(okButton).toBeTruthy();\n      });\n\n      it('doesnt have a cancel button', () => {\n        const wrapper = mount(TDialog, { props });\n\n        const { cancelButton } = wrapper.vm.$refs;\n\n        expect(cancelButton).toBeUndefined();\n      });\n    });\n\n    describe('Confirm type', () => {\n      const props = {\n        type: 'confirm',\n      };\n\n      it('has an ok button', () => {\n        const wrapper = mount(TDialog, { props });\n\n        const { okButton } = wrapper.vm.$refs;\n\n        expect(okButton).toBeTruthy();\n      });\n\n      it('has a cancel button', () => {\n        const wrapper = mount(TDialog, { props });\n\n        const { cancelButton } = wrapper.vm.$refs;\n\n        expect(cancelButton).toBeTruthy();\n      });\n    });\n\n    describe('Prompt type', () => {\n      const props = {\n        type: 'prompt',\n      };\n\n      it('has an ok button', () => {\n        const wrapper = mount(TDialog, { props });\n\n        const { okButton } = wrapper.vm.$refs;\n\n        expect(okButton).toBeTruthy();\n      });\n\n      it('has a cancel button', () => {\n        const wrapper = mount(TDialog, { props });\n\n        const { cancelButton } = wrapper.vm.$refs;\n\n        expect(cancelButton).toBeTruthy();\n      });\n    });\n  });\n\n  describe('Dialog Icon', () => {\n    it('doesnt add an icon by default', () => {\n      const wrapper = mount(TDialog);\n\n      expect(wrapper.vm.$refs.iconWrapperRef).toBeFalsy();\n    });\n\n    it.each(['success', 'question', 'info', 'warning', 'error'])('adds the icon', (icon) => {\n      const wrapper = mount(TDialog, {\n        props: {\n          icon,\n        },\n      });\n\n      expect(wrapper.vm.$refs.iconWrapperRef).toBeTruthy();\n\n      expect((wrapper.vm.$refs.iconWrapperRef as HTMLDivElement).children[0].tagName).toBe('svg');\n    });\n\n    it.each(['success', 'question', 'info', 'warning', 'error'])('adds the icon when useSolidIcon is iset', (icon) => {\n      const wrapper = mount(TDialog, {\n        props: {\n          icon,\n          useSolidIcon: true,\n        },\n      });\n\n      expect(wrapper.vm.$refs.iconWrapperRef).toBeTruthy();\n\n      expect((wrapper.vm.$refs.iconWrapperRef as HTMLDivElement).children[0].tagName).toBe('svg');\n    });\n  });\n\n  describe('promise behaviour on reject', () => {\n    const emitter = new Emitter();\n\n    const params = {\n      props: {\n        type: 'confirm',\n        name: 'my-dialog',\n      },\n      global: {\n        provide: {\n          // Emulates the plugin system\n          emitter,\n        },\n      },\n    };\n\n    it('resolves the promise when is ok by default', async () => {\n      const wrapper = mount(TDialog, params);\n\n      // @see vue/src/plugin.ts show helper\n      const resolve = jest.fn();\n      const reject = jest.fn();\n\n      emitter.emit('dialog:show', 'my-dialog', resolve, reject);\n      await waitUntilModalIsShown(wrapper);\n\n      wrapper.vm.hide(DialogHideReason.Ok);\n      await waitUntilModalIsHidden(wrapper);\n\n      expect(resolve).toHaveBeenCalled();\n      expect(reject).not.toHaveBeenCalled();\n    });\n\n    it('rejects the promise when is dismissed by default', async () => {\n      const wrapper = mount(TDialog, params);\n\n      // @see vue/src/plugin.ts show helper\n      const resolve = jest.fn();\n      const reject = jest.fn();\n\n      emitter.emit('dialog:show', 'my-dialog', resolve, reject);\n      await waitUntilModalIsShown(wrapper);\n\n      wrapper.vm.hide(DialogHideReason.Outside);\n      await waitUntilModalIsHidden(wrapper);\n\n      expect(resolve).not.toHaveBeenCalled();\n      expect(reject).toHaveBeenCalled();\n    });\n\n    it('doesnt rejects the promise when is dismissed for alert dialogs', async () => {\n      const wrapper = mount(TDialog, {\n        props: {\n          ...params.props,\n          type: 'alert',\n        },\n        global: params.global,\n      });\n\n      // @see vue/src/plugin.ts show helper\n      const resolve = jest.fn();\n      const reject = jest.fn();\n\n      emitter.emit('dialog:show', 'my-dialog', resolve, reject);\n      await waitUntilModalIsShown(wrapper);\n\n      wrapper.vm.hide(DialogHideReason.Outside);\n      await waitUntilModalIsHidden(wrapper);\n\n      expect(resolve).toHaveBeenCalled();\n      expect(reject).not.toHaveBeenCalled();\n    });\n\n    it('rejects the promise when rejectOnDismiss is set', async () => {\n      const wrapper = mount(TDialog, {\n        props: {\n          ...params.props,\n          rejectOnDismiss: true,\n        },\n        global: params.global,\n      });\n\n      // @see vue/src/plugin.ts show helper\n      const resolve = jest.fn();\n      const reject = jest.fn();\n\n      emitter.emit('dialog:show', 'my-dialog', resolve, reject);\n      await waitUntilModalIsShown(wrapper);\n\n      wrapper.vm.hide(DialogHideReason.Outside);\n      await waitUntilModalIsHidden(wrapper);\n\n      expect(resolve).not.toHaveBeenCalled();\n      expect(reject).toHaveBeenCalled();\n    });\n\n    it('rejects the promise when rejectOnDismiss is set for alerts', async () => {\n      const wrapper = mount(TDialog, {\n        props: {\n          ...params.props,\n          type: 'alert',\n          rejectOnDismiss: true,\n        },\n        global: params.global,\n      });\n\n      // @see vue/src/plugin.ts show helper\n      const resolve = jest.fn();\n      const reject = jest.fn();\n\n      emitter.emit('dialog:show', 'my-dialog', resolve, reject);\n      await waitUntilModalIsShown(wrapper);\n\n      wrapper.vm.hide(DialogHideReason.Outside);\n      await waitUntilModalIsHidden(wrapper);\n\n      expect(resolve).not.toHaveBeenCalled();\n      expect(reject).toHaveBeenCalled();\n    });\n  });\n\n  describe('Promise behaviour on cancel', () => {\n    const emitter = new Emitter();\n\n    const params = {\n      props: {\n        type: 'confirm',\n        name: 'my-dialog',\n      },\n      global: {\n        provide: {\n          // Emulates the plugin system\n          emitter,\n        },\n      },\n    };\n\n    it('rejects the promise when is cancel by default', async () => {\n      const wrapper = mount(TDialog, params);\n\n      // @see vue/src/plugin.ts show helper\n      const resolve = jest.fn();\n      const reject = jest.fn();\n\n      emitter.emit('dialog:show', 'my-dialog', resolve, reject);\n      await waitUntilModalIsShown(wrapper);\n\n      wrapper.vm.hide(DialogHideReason.Cancel);\n      await waitUntilModalIsHidden(wrapper);\n\n      expect(resolve).not.toHaveBeenCalled();\n      expect(reject).toHaveBeenCalled();\n    });\n\n    it('rejects the promise when rejectOnCancel is set', async () => {\n      const wrapper = mount(TDialog, {\n        props: {\n          ...params.props,\n          rejectOnCancel: true,\n        },\n        global: params.global,\n      });\n\n      // @see vue/src/plugin.ts show helper\n      const resolve = jest.fn();\n      const reject = jest.fn();\n\n      emitter.emit('dialog:show', 'my-dialog', resolve, reject);\n      await waitUntilModalIsShown(wrapper);\n\n      wrapper.vm.hide(DialogHideReason.Cancel);\n      await waitUntilModalIsHidden(wrapper);\n\n      expect(resolve).not.toHaveBeenCalled();\n      expect(reject).toHaveBeenCalled();\n    });\n\n    it('resolves the promise when rejectOnCancel is set to `false`', async () => {\n      const wrapper = mount(TDialog, {\n        props: {\n          ...params.props,\n          rejectOnCancel: false,\n        },\n        global: params.global,\n      });\n\n      // @see vue/src/plugin.ts show helper\n      const resolve = jest.fn();\n      const reject = jest.fn();\n\n      emitter.emit('dialog:show', 'my-dialog', resolve, reject);\n      await waitUntilModalIsShown(wrapper);\n\n      wrapper.vm.hide(DialogHideReason.Cancel);\n      await waitUntilModalIsHidden(wrapper);\n\n      expect(resolve).toHaveBeenCalled();\n      expect(reject).not.toHaveBeenCalled();\n    });\n  });\n\n  describe('preconfirm', () => {\n    it('closes the dialog with the response of the confirm method', async () => {\n      const response = { success: true };\n      const preConfirm = () => new Promise((resolve) => {\n        resolve(response);\n      });\n\n      const wrapper = mount(TDialog, {\n        props: {\n          preConfirm,\n        },\n      });\n\n      wrapper.vm.ok();\n\n      await waitUntilModalIsHidden(wrapper);\n\n      expect(wrapper.emitted()).toHaveProperty('hidden');\n\n      expect(wrapper.emitted('hidden')).toEqual([[{\n        hideReason: 'ok',\n        isCancel: false,\n        isDismissed: false,\n        isOk: true,\n        response,\n      }]]);\n\n      expect(wrapper.vm.busy).toBe(false);\n    });\n\n    it('uses the result of function that is not a promise as result', async () => {\n      const response = { success: true };\n      const preConfirm = () => response;\n\n      const wrapper = mount(TDialog, {\n        props: {\n          preConfirm,\n        },\n      });\n\n      wrapper.vm.ok();\n\n      await waitUntilModalIsHidden(wrapper);\n\n      expect(wrapper.emitted()).toHaveProperty('hidden');\n\n      expect(wrapper.emitted('hidden')).toEqual([[{\n        hideReason: 'ok',\n        isCancel: false,\n        isDismissed: false,\n        isOk: true,\n        response,\n      }]]);\n\n      expect(wrapper.vm.busy).toBe(false);\n    });\n\n    it('doesnt closes the dialog when response fails', async () => {\n      const error = new Error('something went wrong!');\n\n      const preConfirm = () => new Promise((_resolve, reject) => {\n        reject(error);\n      });\n\n      const wrapper = mount(TDialog, {\n        props: {\n          preConfirm,\n        },\n      });\n\n      wrapper.vm.ok();\n\n      await wrapper.vm.$nextTick();\n      await wrapper.vm.$nextTick();\n      await wrapper.vm.$nextTick();\n\n      expect(wrapper.emitted()).toHaveProperty('error');\n\n      expect(wrapper.emitted('error')).toEqual([[error]]);\n\n      expect(wrapper.vm.busy).toBe(false);\n\n      await wrapper.vm.$nextTick();\n      await wrapper.vm.$nextTick();\n      await wrapper.vm.$nextTick();\n      await wrapper.vm.$nextTick();\n\n      expect(wrapper.vm.modelValue).toBe(true);\n    });\n  });\n\n  describe('named dialog', () => {\n    const settings = {\n      props: {\n        name: 'named-dialog',\n        modelValue: false,\n      },\n      global: {\n        plugins: [plugin],\n      },\n    };\n\n    it('opens the dialog by his name', async () => {\n      const wrapper = mount(TDialog, settings);\n\n      wrapper.vm.$dialog.show('named-dialog');\n\n      await waitUntilModalIsShown(wrapper);\n\n      expect(wrapper.emitted()).toHaveProperty('shown');\n    });\n\n    it('doesnt opens the dialog if name is different', async () => {\n      const wrapper = mount(TDialog, settings);\n\n      wrapper.vm.$dialog.show('another-dialog');\n\n      await wrapper.vm.$nextTick();\n      await wrapper.vm.$nextTick();\n      await wrapper.vm.$nextTick();\n      await wrapper.vm.$nextTick();\n      await wrapper.vm.$nextTick();\n\n      expect(wrapper.emitted()).not.toHaveProperty('shown');\n    });\n\n    it('return a promise', async () => {\n      const wrapper = mount(TDialog, settings);\n\n      const promise = wrapper.vm.$dialog.show('named-dialog');\n\n      expect(promise).toBeInstanceOf(Promise);\n    });\n\n    it('hides the dialog by his name', async () => {\n      const wrapper = mount(TDialog, {\n        props: {\n          ...settings.props,\n          modelValue: true,\n        },\n        global: settings.global,\n      });\n\n      wrapper.vm.$dialog.hide('named-dialog');\n\n      await waitUntilModalIsHidden(wrapper);\n\n      expect(wrapper.emitted()).toHaveProperty('hidden');\n    });\n\n    it('doesnt hides the dialog if using another name', async () => {\n      const wrapper = mount(TDialog, {\n        props: {\n          ...settings.props,\n          modelValue: true,\n        },\n        global: settings.global,\n      });\n\n      wrapper.vm.$dialog.hide('another-dialog');\n\n      await wrapper.vm.$nextTick();\n      await wrapper.vm.$nextTick();\n      await wrapper.vm.$nextTick();\n      await wrapper.vm.$nextTick();\n      await wrapper.vm.$nextTick();\n\n      expect(wrapper.emitted()).not.toHaveProperty('hidden');\n    });\n  });\n\n  describe('vModel', () => {\n    it('shows the component when updated the v-model to true', async () => {\n      const wrapper = mount(TDialog, {\n        props: {\n          modelValue: false,\n        },\n      });\n\n      wrapper.setProps({\n        modelValue: true,\n      });\n\n      await waitUntilModalIsShown(wrapper);\n\n      expect(wrapper.emitted()).toHaveProperty('shown');\n    });\n\n    it('hides the component when updated the v-model to false', async () => {\n      const wrapper = mount(TDialog, {\n        props: {\n          modelValue: true,\n        },\n      });\n\n      wrapper.setProps({\n        modelValue: false,\n      });\n\n      await waitUntilModalIsHidden(wrapper);\n\n      expect(wrapper.emitted()).toHaveProperty('hidden');\n    });\n  });\n\n  describe('focus on open', () => {\n    let originalDivFocus: any;\n    let originalInputFocus: any;\n    let originalTextareaFocus: any;\n    beforeEach(() => {\n      originalInputFocus = window.HTMLInputElement.prototype.focus;\n      originalTextareaFocus = window.HTMLTextAreaElement.prototype.focus;\n      originalDivFocus = window.HTMLInputElement.prototype.focus;\n    });\n\n    afterEach(() => {\n      window.HTMLTextAreaElement.prototype.focus = originalTextareaFocus;\n      window.HTMLInputElement.prototype.focus = originalInputFocus;\n      window.HTMLInputElement.prototype.focus = originalDivFocus;\n    });\n\n    it('focus the div when focus on open is set an is not a prompt type', async () => {\n      const focusInputMock = jest.fn();\n      const focusDivMock = jest.fn();\n      window.HTMLInputElement.prototype.focus = focusInputMock;\n      window.HTMLDivElement.prototype.focus = focusDivMock;\n\n      const wrapper = mount(TDialog, {\n        props: {\n          modelValue: false,\n          type: DialogType.Alert,\n        },\n      });\n\n      wrapper.vm.show();\n\n      await waitUntilModalIsShown(wrapper);\n\n      expect(focusInputMock).not.toHaveBeenCalled();\n      expect(focusDivMock).toHaveBeenCalled();\n    });\n\n    it('focus the input when focus on open is set and is a prompt type', async () => {\n      const focusInputMock = jest.fn();\n      const focusDivMock = jest.fn();\n      window.HTMLInputElement.prototype.focus = focusInputMock;\n      window.HTMLDivElement.prototype.focus = focusDivMock;\n\n      const wrapper = mount(TDialog, {\n        props: {\n          modelValue: false,\n          type: DialogType.Prompt,\n        },\n      });\n\n      wrapper.vm.show();\n\n      await waitUntilModalIsShown(wrapper);\n\n      expect(focusInputMock).toHaveBeenCalled();\n      expect(focusDivMock).not.toHaveBeenCalled();\n    });\n\n    it('focus first focusable item when using the slot and is a prompt type', async () => {\n      const focusDivMock = jest.fn();\n      const focusTextareaMock = jest.fn();\n      window.HTMLDivElement.prototype.focus = focusDivMock;\n      window.HTMLTextAreaElement.prototype.focus = focusTextareaMock;\n\n      const wrapper = mount(TDialog, {\n        props: {\n          modelValue: false,\n          type: DialogType.Prompt,\n        },\n        slots: {\n          input: () => h('textarea'),\n        },\n      });\n\n      wrapper.vm.show();\n\n      await waitUntilModalIsShown(wrapper);\n\n      expect(focusTextareaMock).toHaveBeenCalled();\n      expect(focusDivMock).not.toHaveBeenCalled();\n    });\n\n    it('focus the dialog if no focusable item when using the slot and is a prompt type', async () => {\n      const focusDivMock = jest.fn();\n      window.HTMLDivElement.prototype.focus = focusDivMock;\n\n      const wrapper = mount(TDialog, {\n        props: {\n          modelValue: false,\n          type: DialogType.Prompt,\n        },\n        slots: {\n          input: () => h('div'),\n        },\n      });\n\n      wrapper.vm.show();\n\n      await waitUntilModalIsShown(wrapper);\n\n      expect(focusDivMock).toHaveBeenCalled();\n    });\n\n    it('doesnt focus anything if `focusOnOpen` is set to `false', async () => {\n      const focusInputMock = jest.fn();\n      const focusDivMock = jest.fn();\n      window.HTMLInputElement.prototype.focus = focusInputMock;\n      window.HTMLDivElement.prototype.focus = focusDivMock;\n\n      const wrapper = mount(TDialog, {\n        props: {\n          modelValue: false,\n          type: DialogType.Prompt,\n          focusOnOpen: false,\n        },\n      });\n\n      wrapper.vm.show();\n\n      await waitUntilModalIsShown(wrapper);\n\n      expect(focusInputMock).not.toHaveBeenCalled();\n      expect(focusDivMock).not.toHaveBeenCalled();\n    });\n  });\n\n  describe('Input related props', () => {\n    it('assigns the inputValue to the inputModel', () => {\n      const wrapper = mount(TDialog, {\n        props: {\n          inputValue: 'hello',\n          type: DialogType.Prompt,\n        },\n      });\n\n      expect(wrapper.vm.inputModel).toBe('hello');\n      expect(wrapper.find('input').element.value).toBe('hello');\n    });\n\n    it('resets to the value on the inputValue when modal is closed', async () => {\n      const wrapper = mount(TDialog, {\n        props: {\n          inputValue: 'hello',\n          type: DialogType.Prompt,\n        },\n      });\n\n      expect(wrapper.vm.inputModel).toBe('hello');\n      wrapper.find('input').element.value = 'world';\n      wrapper.find('input').trigger('input');\n      expect(wrapper.vm.inputModel).toBe('world');\n\n      wrapper.vm.hide();\n\n      await waitUntilModalIsHidden(wrapper);\n\n      expect(wrapper.vm.inputModel).toBe('hello');\n    });\n\n    it('passes the inputType to the input', async () => {\n      const wrapper = mount(TDialog, {\n        props: {\n          inputType: 'password',\n          type: DialogType.Prompt,\n        },\n      });\n\n      expect(wrapper.find('input').attributes('type')).toBe('password');\n    });\n\n    it('passes the inputAttributes to the input', async () => {\n      const wrapper = mount(TDialog, {\n        props: {\n          inputAttributes: {\n            'data-foo': 'bar',\n            width: '100',\n          },\n          type: DialogType.Prompt,\n        },\n      });\n\n      expect(wrapper.find('input').attributes('data-foo')).toBe('bar');\n      expect(wrapper.find('input').attributes('width')).toBe('100');\n    });\n  });\n\n  describe('Input validation', () => {\n    it('doesnt hides the dialog when validation returns a message', async () => {\n      const inputValidator = () => 'error!';\n      const wrapper = mount(TDialog, {\n        props: {\n          type: DialogType.Prompt,\n          inputValidator,\n        },\n      });\n\n      expect(wrapper.html()).not.toContain('error!');\n\n      wrapper.vm.ok();\n\n      await wrapper.vm.$nextTick();\n      await wrapper.vm.$nextTick();\n      await wrapper.vm.$nextTick();\n\n      expect(wrapper.emitted()).toHaveProperty('validation-error');\n\n      expect(wrapper.emitted('validation-error')).toEqual([['error!']]);\n\n      expect(wrapper.vm.busy).toBe(false);\n\n      expect(wrapper.html()).toContain('error!');\n\n      await wrapper.vm.$nextTick();\n      await wrapper.vm.$nextTick();\n      await wrapper.vm.$nextTick();\n      await wrapper.vm.$nextTick();\n\n      expect(wrapper.vm.modelValue).toBe(true);\n    });\n\n    it('resets the validation error when ok', async () => {\n      const inputValidator = () => null;\n      const wrapper = mount(TDialog, {\n        props: {\n          type: DialogType.Prompt,\n          inputValidator,\n        },\n      });\n\n      wrapper.vm.setValidationError('error!');\n\n      await wrapper.vm.$nextTick();\n\n      expect(wrapper.html()).toContain('error!');\n\n      wrapper.vm.ok();\n\n      await wrapper.vm.$nextTick();\n      await wrapper.vm.$nextTick();\n      await wrapper.vm.$nextTick();\n\n      expect(wrapper.html()).not.toContain('error!');\n    });\n\n    it('validates on input', async () => {\n      const inputValidator = (val: string) => (val === 'fail' ? 'fail' : null);\n      const wrapper = mount(TDialog, {\n        props: {\n          type: DialogType.Prompt,\n          inputValidator,\n        },\n      });\n\n      wrapper.find('input').element.value = 'fail';\n      wrapper.find('input').trigger('input');\n\n      await wrapper.vm.$nextTick();\n\n      expect(wrapper.html()).toContain('fail');\n    });\n\n    it('resets the validation when input', async () => {\n      const inputValidator = () => null;\n      const wrapper = mount(TDialog, {\n        props: {\n          type: DialogType.Prompt,\n          inputValidator,\n        },\n      });\n\n      wrapper.vm.setValidationError('error!');\n\n      await wrapper.vm.$nextTick();\n\n      expect(wrapper.html()).toContain('error!');\n\n      wrapper.find('input').element.value = 'something';\n      wrapper.find('input').trigger('input');\n\n      await wrapper.vm.$nextTick();\n\n      expect(wrapper.html()).not.toContain('error!');\n    });\n  });\n\n  describe('Misc validations', () => {\n    it('doesnt closes the dialog if is busy', async () => {\n      const wrapper = mount(TDialog);\n\n      wrapper.vm.busy = true;\n\n      wrapper.vm.hide();\n\n      await wrapper.vm.$nextTick();\n      await wrapper.vm.$nextTick();\n      await wrapper.vm.$nextTick();\n      await wrapper.vm.$nextTick();\n      await wrapper.vm.$nextTick();\n      await wrapper.vm.$nextTick();\n      await wrapper.vm.$nextTick();\n\n      expect(wrapper.emitted()).not.toHaveProperty('hidden');\n    });\n\n    it('closes the dialog when is busy when hide reason is \"ok\"', async () => {\n      const wrapper = mount(TDialog);\n\n      wrapper.vm.busy = true;\n\n      wrapper.vm.hide(DialogHideReason.Ok);\n\n      await waitUntilModalIsHidden(wrapper);\n\n      expect(wrapper.emitted()).toHaveProperty('hidden');\n    });\n\n    it('uses the modal hide reason', async () => {\n      const wrapper = mount(TDialog);\n\n      wrapper.vm.$refs.modalRef.$refs.overlay.dispatchEvent(new KeyboardEvent('keydown', {\n        key: 'Escape',\n      }));\n\n      // wrapper.vm.$refs.modalRef.onKeydownEscapeHandler();\n\n      await waitUntilModalIsHidden(wrapper);\n\n      expect(wrapper.emitted('hidden')).toEqual([[{\n        hideReason: 'esc',\n        isCancel: false,\n        isDismissed: true,\n        isOk: false,\n      }]]);\n    });\n  });\n});\n"
  },
  {
    "path": "src/__tests/components/TDropdown.spec.ts",
    "content": "/* eslint-disable @typescript-eslint/no-non-null-assertion */\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport { mount, VueWrapper } from '@vue/test-utils';\nimport { TDropdownConfig, TDropdownPopperDefaultOptions } from '@variantjs/core';\nimport { h } from 'vue';\nimport TDropdown from '@/components/TDropdown.vue';\nimport { scopedParamsAsString, parseScopedParams } from '../testUtils';\n\ndescribe('TDropdown.vue', () => {\n  let updatePopperMock: jest.Mock<any, any>;\n  const originalUpdatePopperMethod = TDropdown.methods!.updatePopper;\n\n  beforeEach(() => {\n    updatePopperMock = jest.fn().mockReturnValue(Promise.resolve());\n\n    TDropdown.methods!.updatePopper = updatePopperMock;\n  });\n\n  afterEach(() => {\n    updatePopperMock.mockRestore();\n    TDropdown.methods!.updatePopper = originalUpdatePopperMethod;\n  });\n\n  it('renders the component', () => {\n    const wrapper = mount(TDropdown);\n\n    expect(wrapper.find('button').exists()).toBe(true);\n    expect(wrapper.find('button').isVisible()).toBe(true);\n    expect(wrapper.find('div').exists()).toBe(true);\n    expect(wrapper.vm.$refs.trigger).toBeTruthy();\n    expect(wrapper.vm.$refs.dropdown).toBeTruthy();\n  });\n\n  it('has default classes', () => {\n    const wrapper = mount(TDropdown);\n    const { trigger, dropdown } = wrapper.vm.$refs;\n\n    expect(trigger.className).toBe(TDropdownConfig.classes.trigger);\n    expect(dropdown.className).toBe(TDropdownConfig.classes.dropdown);\n    expect(wrapper.vm.configuration.classesList).toEqual(TDropdownConfig.classes);\n  });\n\n  it('initializes the dropdown', async () => {\n    const wrapper = mount(TDropdown);\n\n    expect(wrapper.vm.shown).toBe(false);\n    expect(wrapper.vm.popperIsAdjusted).toBe(false);\n    expect(wrapper.vm.popper).toBe(null);\n  });\n\n  it('uses the content of the trigger slot inside the trigger button', () => {\n    const wrapper = mount(TDropdown, {\n      slots: {\n        trigger: 'Press me!',\n      },\n    });\n    expect(wrapper.find('button').text()).toBe('Press me!');\n  });\n\n  it('uses the content of the text prop inside the trigger button', () => {\n    const wrapper = mount(TDropdown, {\n      props: {\n        text: 'Press me!',\n      },\n    });\n\n    expect(wrapper.find('button').text()).toBe('Press me!');\n  });\n\n  it('exposes the `isShow` variable and the configuration ', () => {\n    const wrapper = mount(TDropdown, {\n      slots: {\n        trigger: (params) => scopedParamsAsString(params),\n      },\n    });\n\n    const scopeParamKeys = parseScopedParams(wrapper.text());\n\n    expect(scopeParamKeys).toEqual({\n      isShow: 'boolean',\n      configuration: 'object',\n      popper: 'object',\n    });\n  });\n\n  it('exposes the `toggle`, `show` and `hide` methods and the configuration to the dropdown slot ', () => {\n    const wrapper = mount(TDropdown, {\n      slots: {\n        default: (params) => scopedParamsAsString(params),\n      },\n    });\n\n    const scopeParamKeys = parseScopedParams(wrapper.text());\n\n    expect(scopeParamKeys).toEqual({\n      show: 'function',\n      hide: 'function',\n      toggle: 'function',\n      configuration: 'object',\n      popper: 'object',\n    });\n  });\n\n  it('renders an empty button if no slot or text', () => {\n    const wrapper = mount(TDropdown);\n\n    expect(wrapper.find('button').text()).toBe('');\n  });\n\n  it('prioritizes the slot over the text prop', () => {\n    const wrapper = mount(TDropdown, {\n      props: {\n        text: 'Press me2!',\n      },\n      slots: {\n        trigger: 'Press me!',\n      },\n    });\n\n    expect(wrapper.find('button').text()).toBe('Press me!');\n  });\n\n  it('uses the content of the default slot inside the dropdown', () => {\n    const wrapper = mount(TDropdown, {\n      slots: {\n        default: 'Dropdown stuffy',\n      },\n    });\n\n    const { dropdown } = wrapper.vm.$refs;\n    expect(dropdown.innerHTML).toBe('Dropdown stuffy');\n  });\n\n  it('shows the dropdown when the trigger is pressed', async () => {\n    const wrapper = mount(TDropdown, {\n      props: {\n        toggleOnClick: true,\n        toggleOnFocus: false,\n      },\n    });\n\n    const trigger = wrapper.get('button');\n\n    await trigger.trigger('click');\n\n    expect(wrapper.vm.shown).toBe(true);\n  });\n\n  it('hides the dropdown when the trigger is pressed and is openede ', async () => {\n    const wrapper = mount(TDropdown, {\n      props: {\n        toggleOnClick: true,\n        show: true,\n      },\n    });\n\n    const trigger = wrapper.get('button');\n\n    await trigger.trigger('click');\n\n    expect(wrapper.vm.shown).toBe(false);\n  });\n\n  it('doesnt teleports the dropdown by default', () => {\n    const wrapper = mount(TDropdown);\n\n    expect(wrapper.find('div').exists()).toBe(true);\n  });\n\n  it('teleports the dropdown to the body if teleport option is set', () => {\n    mount(TDropdown, {\n      props: {\n        teleport: true,\n      },\n      slots: {\n        default: 'The body',\n      },\n    });\n\n    expect(document.body.children[0].textContent).toBe('The body');\n  });\n\n  it('teleports the dropdown to the selector in the teleportTo prop', () => {\n    const div = document.createElement('div');\n    div.id = 'teleport-here';\n\n    document.body.appendChild(div);\n\n    mount(TDropdown, {\n      props: {\n        teleport: true,\n        teleportTo: '#teleport-here',\n      },\n      slots: {\n        default: 'The body',\n      },\n    });\n\n    expect(document.querySelector('#teleport-here')!.textContent).toBe('The body');\n  });\n\n  it('teleports the dropdown to the element in the teleportTo prop', () => {\n    const div = document.createElement('div');\n    div.id = 'dont-teleport-here';\n\n    document.body.appendChild(div);\n\n    mount(TDropdown, {\n      props: {\n        teleport: true,\n        teleportTo: div,\n      },\n      slots: {\n        default: 'The body',\n      },\n    });\n\n    expect(document.querySelector('#teleport-here')!.textContent).toBe('The body');\n  });\n\n  it('the trigger is a button with type `button`', async () => {\n    const wrapper = mount(TDropdown);\n\n    const trigger = wrapper.get('button');\n\n    expect(trigger.attributes().type).toBe('button');\n    expect(trigger.element.tagName).toBe('BUTTON');\n  });\n\n  it('disables the dropdown', async () => {\n    const wrapper = mount(TDropdown, {\n      props: {\n        disabled: true,\n      },\n    });\n\n    const trigger = wrapper.get('button');\n\n    const { dropdown } = wrapper.vm.$refs;\n\n    expect(trigger.attributes().disabled).toBeDefined();\n\n    await trigger.trigger('click');\n\n    expect(wrapper.vm.shown).toBe(false);\n\n    expect(dropdown.style.display).toBe('none');\n  });\n\n  it('applies the dropdownAttributes to the dropdown', () => {\n    const wrapper = mount(TDropdown, {\n      props: {\n        dropdownAttributes: {\n          id: 'my-id',\n          'data-foo': 'bar',\n        },\n      },\n    });\n\n    const { dropdown } = wrapper.vm.$refs;\n\n    expect(dropdown.getAttribute('id')).toBe('my-id');\n    expect(dropdown.getAttribute('data-foo')).toBe('bar');\n  });\n\n  it('applies the attributes to the trigger button', () => {\n    const wrapper = mount(TDropdown, {\n      attrs: {\n        id: 'my-id',\n        'data-foo': 'bar',\n      },\n    });\n\n    const trigger = wrapper.get('button');\n\n    expect(trigger.attributes().id).toBe('my-id');\n    expect(trigger.attributes()['data-foo']).toBe('bar');\n  });\n\n  it('applies the attributes that comes from the configuration the trigger button', () => {\n    const wrapper = mount(TDropdown, {\n      global: {\n        provide: {\n          configuration: {\n            TDropdown: {\n              id: 'my-id',\n              'data-foo': 'bar',\n            },\n          },\n        },\n      },\n    });\n\n    const trigger = wrapper.get('button');\n\n    expect(trigger.attributes().id).toBe('my-id');\n    expect(trigger.attributes()['data-foo']).toBe('bar');\n  });\n\n  it('prioritizes the local attributes', () => {\n    const wrapper = mount(TDropdown, {\n      global: {\n        provide: {\n          configuration: {\n            TDropdown: {\n              id: 'my-id',\n            },\n          },\n        },\n      },\n      attrs: {\n        id: 'my-local-id',\n      },\n    });\n\n    const trigger = wrapper.get('button');\n\n    expect(trigger.attributes().id).toBe('my-local-id');\n  });\n\n  it('uses the set tagName ', () => {\n    const wrapper = mount(TDropdown, {\n      props: {\n        tagName: 'a',\n      },\n    });\n\n    const { trigger } = wrapper.vm.$refs;\n\n    expect(trigger.tagName).toBe('A');\n  });\n\n  it('uses the set dropdownTagName ', () => {\n    const wrapper = mount(TDropdown, {\n      props: {\n        dropdownTagName: 'ul',\n      },\n    });\n\n    const { dropdown } = wrapper.vm.$refs;\n\n    expect(dropdown.tagName).toBe('UL');\n  });\n\n  it('doesnt toggle the dropdown on click if toggleOnClick is set to `false`', async () => {\n    const wrapper = mount(TDropdown, {\n      props: {\n        toggleOnClick: false,\n      },\n    });\n\n    const trigger = wrapper.get('button');\n\n    await trigger.trigger('click');\n\n    expect(wrapper.vm.shown).toBe(false);\n\n    await trigger.trigger('click');\n\n    expect(wrapper.vm.shown).toBe(false);\n  });\n\n  it('shows the dropdown on click by default', async () => {\n    const wrapper = mount(TDropdown, {\n      props: {\n        // To avoid false positives\n        toggleOnFocus: false,\n      },\n    });\n\n    const trigger = wrapper.get('button');\n\n    await trigger.trigger('click');\n\n    expect(wrapper.vm.shown).toBe(true);\n  });\n\n  it('hides the dropdown on click by default', async () => {\n    const wrapper = mount(TDropdown, {\n      props: {\n        // To avoid false positives\n        toggleOnFocus: false,\n        show: true,\n      },\n    });\n\n    const trigger = wrapper.get('button');\n\n    await trigger.trigger('click');\n\n    expect(wrapper.vm.shown).toBe(false);\n  });\n\n  it('shows the dropdown on focus by default', async () => {\n    const wrapper = mount(TDropdown, {\n      props: {\n        // To avoid false positives\n        toggleOnClick: false,\n      },\n    });\n\n    const trigger = wrapper.get('button');\n\n    await trigger.trigger('focus');\n\n    expect(wrapper.vm.shown).toBe(true);\n  });\n\n  it('doesnt hide the dropdown when focus when doesnt have the `toggleOnFocus` options', async () => {\n    const wrapper = mount(TDropdown, {\n      props: {\n        show: true,\n        toggleOnFocus: false,\n      },\n    });\n\n    const trigger = wrapper.get('button');\n\n    await trigger.trigger('focus');\n\n    expect(wrapper.vm.shown).toBe(true);\n  });\n\n  it('hides the dropdown on blur by default', async () => {\n    const wrapper = mount(TDropdown, {\n      props: {\n        show: true,\n        // To avoid false positives\n        toggleOnClick: false,\n      },\n    });\n\n    const trigger = wrapper.get('button');\n\n    await trigger.trigger('blur');\n\n    expect(wrapper.vm.shown).toBe(false);\n  });\n\n  it('doesnt shows the dropdown on hover by default', async () => {\n    const wrapper = mount(TDropdown);\n\n    const trigger = wrapper.get('button');\n\n    await trigger.trigger('hover');\n\n    expect(wrapper.vm.shown).toBe(false);\n  });\n\n  it('doesnt hides the drodown on hoverout by default', async () => {\n    const wrapper = mount(TDropdown, {\n      props: {\n        show: true,\n      },\n    });\n\n    const trigger = wrapper.get('button');\n\n    await trigger.trigger('hover');\n\n    expect(wrapper.vm.shown).toBe(true);\n  });\n\n  it('toggles the dropdown on focus if option is set', async () => {\n    const wrapper = mount(TDropdown, {\n      props: {\n        toggleOnFocus: true,\n      },\n    });\n\n    const trigger = wrapper.get('button');\n\n    await trigger.trigger('focus');\n\n    expect(wrapper.vm.shown).toBe(true);\n\n    await trigger.trigger('blur');\n\n    expect(wrapper.vm.shown).toBe(false);\n  });\n\n  it('doesnt hides the dropdown if blur in the the dropdown', async () => {\n    const wrapper = mount(TDropdown, {\n      props: {\n        show: true,\n        toggleOnFocus: true,\n      },\n    });\n\n    const triggerButton = wrapper.get('button');\n\n    const { dropdown } = wrapper.vm.$refs;\n\n    await triggerButton.trigger('blur', {\n      relatedTarget: dropdown,\n    });\n\n    expect(wrapper.vm.shown).toBe(true);\n  });\n\n  it('adds and remove blur listener to focusable elements inside the dropdown when shown', async () => {\n    const addEventListenerMock = jest.fn();\n    const removeEventListenerMock = jest.fn();\n    window.HTMLInputElement.prototype.addEventListener = addEventListenerMock;\n    window.HTMLInputElement.prototype.removeEventListener = removeEventListenerMock;\n    const wrapper = mount(TDropdown, {\n      slots: {\n        default: h('input'),\n      },\n    });\n\n    wrapper.vm.doShow();\n\n    await wrapper.vm.$nextTick();\n    await wrapper.vm.$nextTick();\n\n    expect(addEventListenerMock).toHaveBeenCalled();\n\n    wrapper.vm.doHide();\n\n    await wrapper.vm.$nextTick();\n    await wrapper.vm.$nextTick();\n\n    expect(removeEventListenerMock).toHaveBeenCalled();\n  });\n\n  it('doesnt hides the dropdown if blur in the the trigger', async () => {\n    const wrapper = mount(TDropdown, {\n      props: {\n        show: true,\n        toggleOnFocus: true,\n      },\n    });\n\n    const triggerButton = wrapper.get('button');\n\n    const { trigger } = wrapper.vm.$refs;\n\n    await triggerButton.trigger('blur', {\n      relatedTarget: trigger,\n    });\n\n    expect(wrapper.vm.shown).toBe(true);\n  });\n\n  it('doesnt hides the dropdown if blur in an element inside the dropdown', async () => {\n    const wrapper = mount(TDropdown, {\n      props: {\n        show: true,\n        toggleOnFocus: true,\n      },\n      slots: {\n        default: h('button', 'focus me'),\n      },\n    });\n\n    const triggerButton = wrapper.get('button');\n\n    const { dropdown } = wrapper.vm.$refs;\n\n    const button = dropdown.querySelector('button');\n\n    await triggerButton.trigger('blur', {\n      relatedTarget: button,\n    });\n\n    expect(wrapper.vm.shown).toBe(true);\n  });\n\n  it('hides the dropdown on trigger blur', async () => {\n    const wrapper = mount(TDropdown, {\n      props: {\n        show: true,\n        toggleOnFocus: true,\n      },\n    });\n\n    const trigger = wrapper.get('button');\n\n    await trigger.trigger('blur');\n\n    expect(wrapper.vm.shown).toBe(false);\n  });\n\n  it('hides the dropdown on dropdown blur', async () => {\n    const wrapper = mount(TDropdown, {\n      props: {\n        show: true,\n        toggleOnFocus: true,\n      },\n    });\n\n    const dropdown = wrapper.get('div');\n\n    await dropdown.trigger('blur');\n\n    expect(wrapper.vm.shown).toBe(false);\n  });\n\n  it('hides the dropdown if blur on an element that is not a child', async () => {\n    const wrapper = mount(TDropdown, {\n      props: {\n        show: true,\n        toggleOnFocus: true,\n      },\n      slots: {\n        default: h('button', {}, 'blur me'),\n      },\n    });\n\n    const button = wrapper.find('button') as any;\n\n    button.trigger('blur');\n\n    expect(wrapper.vm.shown).toBe(false);\n  });\n\n  it('removes the child element blur handler if toggleOnFocus changes', async () => {\n    const wrapper = mount(TDropdown, {\n      props: {\n        show: true,\n        toggleOnFocus: true,\n      },\n      slots: {\n        default: h('button', {}, 'blur me'),\n      },\n    });\n\n    wrapper.setProps({\n      toggleOnFocus: false,\n    });\n\n    const { dropdown } = wrapper.vm.$refs;\n\n    const button = dropdown.querySelector('button') as HTMLButtonElement;\n\n    button.dispatchEvent(new FocusEvent('blur'));\n\n    expect(wrapper.vm.shown).toBe(true);\n    expect(wrapper.vm.focusableElements).toEqual([]);\n  });\n\n  it('doesnt toggle the dropdown on hover by default', async () => {\n    const wrapper = mount(TDropdown);\n\n    const trigger = wrapper.get('button');\n\n    await trigger.trigger('hover');\n\n    expect(wrapper.vm.shown).toBe(false);\n\n    await trigger.trigger('blur');\n\n    expect(wrapper.vm.shown).toBe(false);\n  });\n\n  it('toggles the dropdown on hover immediatly if option is set', async () => {\n    const wrapper = mount(TDropdown, {\n      props: {\n        toggleOnHover: true,\n        hideOnLeaveTimeout: null,\n      },\n    });\n\n    const trigger = wrapper.get('button');\n\n    await trigger.trigger('mouseover');\n\n    expect(wrapper.vm.shown).toBe(true);\n\n    await trigger.trigger('mouseleave');\n\n    expect(wrapper.vm.shown).toBe(false);\n  });\n\n  it('doesnt toggles the dropdown on hover if option is not set', async () => {\n    const wrapper = mount(TDropdown, {\n      props: {\n        toggleOnHover: false,\n        hideOnLeaveTimeout: null,\n      },\n    });\n\n    const trigger = wrapper.get('button');\n\n    await trigger.trigger('mouseover');\n\n    expect(wrapper.vm.shown).toBe(false);\n  });\n\n  it('hides the dropdown if mouseleave the dropdown', async () => {\n    const wrapper = mount(TDropdown, {\n      props: {\n        show: true,\n        toggleOnHover: true,\n        hideOnLeaveTimeout: null,\n      },\n    });\n\n    const dropdown = wrapper.get('div');\n\n    await dropdown.trigger('mouseleave');\n\n    expect(wrapper.vm.shown).toBe(false);\n  });\n\n  it('hides the dropdown after the timeout', async () => {\n    jest.useFakeTimers();\n\n    const wrapper = mount(TDropdown, {\n      props: {\n        show: true,\n        toggleOnHover: true,\n        hideOnLeaveTimeout: 500,\n      },\n    });\n\n    const dropdown = wrapper.get('div');\n\n    await dropdown.trigger('mouseleave');\n\n    expect(wrapper.vm.shown).toBe(true);\n\n    jest.advanceTimersByTime(499);\n\n    expect(wrapper.vm.shown).toBe(true);\n\n    jest.advanceTimersByTime(1);\n\n    expect(wrapper.vm.shown).toBe(false);\n\n    jest.useRealTimers();\n  });\n\n  it('clears the hidetimeout if something receives mouseover ', async () => {\n    jest.useFakeTimers();\n\n    const wrapper = mount(TDropdown, {\n      props: {\n        show: true,\n        toggleOnHover: true,\n        hideOnLeaveTimeout: 500,\n      },\n    });\n\n    const button = wrapper.get('button');\n    const dropdown = wrapper.get('div');\n\n    await dropdown.trigger('mouseleave');\n\n    expect(wrapper.vm.shown).toBe(true);\n\n    jest.advanceTimersByTime(499);\n\n    await button.trigger('mouseover');\n\n    expect(wrapper.vm.shown).toBe(true);\n\n    jest.advanceTimersByTime(500);\n\n    expect(wrapper.vm.shown).toBe(true);\n\n    jest.useRealTimers();\n  });\n\n  it('doesnt hides the dropdown if mouseleave the dropdown', async () => {\n    const wrapper = mount(TDropdown, {\n      props: {\n        show: true,\n        toggleOnHover: true,\n        hideOnLeaveTimeout: null,\n      },\n    });\n\n    const triggerButton = wrapper.get('button');\n\n    const { dropdown } = wrapper.vm.$refs;\n\n    await triggerButton.trigger('mouseleave', {\n      relatedTarget: dropdown,\n    });\n\n    expect(wrapper.vm.shown).toBe(true);\n  });\n\n  it('doesnt hides the dropdown if mouseleave the trigger', async () => {\n    const wrapper = mount(TDropdown, {\n      props: {\n        show: true,\n        toggleOnHover: true,\n        hideOnLeaveTimeout: null,\n      },\n    });\n\n    const triggerButton = wrapper.get('button');\n\n    const { trigger } = wrapper.vm.$refs;\n\n    await triggerButton.trigger('mouseleave', {\n      relatedTarget: trigger,\n    });\n\n    expect(wrapper.vm.shown).toBe(true);\n  });\n\n  it('has a focus method that focus the trigger', async () => {\n    const wrapper = mount(TDropdown);\n    const { trigger } = wrapper.vm.$refs;\n\n    const focusMock = jest.fn();\n    trigger.focus = focusMock;\n\n    wrapper.vm.focus();\n\n    expect(focusMock).toHaveBeenCalled();\n  });\n\n  it('emits native button events', () => {\n    const onClick = jest.fn();\n    const onBlur = jest.fn();\n    const onFocus = jest.fn();\n\n    const wrapper = mount(TDropdown, {\n      attrs: {\n        onClick,\n        onBlur,\n        onFocus,\n      },\n    });\n\n    const { trigger } = wrapper.vm.$refs;\n\n    trigger.dispatchEvent(new MouseEvent('click'));\n    expect(onClick).toHaveBeenCalled();\n\n    trigger.dispatchEvent(new FocusEvent('focus'));\n    expect(onFocus).toHaveBeenCalled();\n\n    trigger.dispatchEvent(new FocusEvent('blur'));\n    expect(onBlur).toHaveBeenCalled();\n  });\n\n  it('triggers custom events', async () => {\n    const onCustom = jest.fn();\n\n    const wrapper = mount(TDropdown, {\n      attrs: {\n        onCustom,\n      },\n    });\n    const { trigger } = wrapper.vm.$refs;\n\n    const evt = new CustomEvent('custom', { detail: 'my-custom-event' });\n    trigger.dispatchEvent(evt);\n\n    expect(onCustom).toHaveBeenCalled();\n  });\n\n  it('display the dropdown if `show` prop is set ', async () => {\n    const wrapper = mount(TDropdown, {\n      props: {\n        show: true,\n      },\n    });\n\n    const { dropdown } = wrapper.vm.$refs;\n\n    expect(wrapper.vm.shown).toBe(true);\n    expect(dropdown.style.display).toBe('');\n  });\n\n  it('emits `update:show` when show property is updated', async () => {\n    const wrapper = mount(TDropdown);\n\n    wrapper.vm.doShow();\n\n    await wrapper.vm.$nextTick();\n\n    await wrapper.vm.$nextTick();\n\n    // assert event has been emitted\n    expect(wrapper.emitted()['update:show']).toBeTruthy();\n\n    // assert event payload\n    expect(wrapper.emitted()['update:show']).toEqual([[true]]);\n\n    wrapper.vm.doHide();\n\n    await wrapper.vm.$nextTick();\n\n    // assert event has been emitted\n    expect(wrapper.emitted()['update:show']).toBeTruthy();\n\n    // assert event payload\n    expect(wrapper.emitted()['update:show']).toEqual([[true], [false]]);\n  });\n\n  it('shows the modal if the `show` props changes', async () => {\n    const wrapper = mount(TDropdown);\n\n    await wrapper.setProps({\n      show: true,\n    });\n\n    expect(wrapper.vm.shown).toBe(true);\n  });\n\n  it('hides the modal if the `show` props changes', async () => {\n    const wrapper = mount(TDropdown, {\n      props: {\n        show: true,\n      },\n    });\n\n    await wrapper.setProps({\n      show: false,\n    });\n\n    expect(wrapper.vm.shown).toBe(false);\n  });\n\n  it('clears the hidetimeout when unmounted', async () => {\n    jest.useFakeTimers();\n\n    const jestMock = jest.fn();\n\n    const wrapper = mount(TDropdown);\n\n    wrapper.vm.hideTimeout = setTimeout(jestMock, 100);\n\n    wrapper.unmount();\n\n    jest.advanceTimersByTime(100);\n\n    expect(jestMock).not.toHaveBeenCalled();\n\n    jest.useRealTimers();\n  });\n\n  it('invalidates invalid dropdown placements', () => {\n    const { validator } = TDropdown.props.placement;\n    expect(validator('invalid')).toBe(false);\n  });\n\n  it.each([\n    'auto',\n    'auto-start',\n    'auto-end',\n    'top',\n    'top-start',\n    'top-end',\n    'bottom',\n    'bottom-start',\n    'bottom-end',\n    'right',\n    'right-start',\n    'right-end',\n    'left',\n    'left-start',\n    'left-end',\n  ])('accept valid dropdown placements', (placement) => {\n    const { validator } = TDropdown.props.placement;\n    expect(validator(placement)).toBe(true);\n  });\n\n  it('has a default the popper configuration', async () => {\n    const wrapper = mount(TDropdown);\n\n    expect(wrapper.vm.popperOptions).toEqual(TDropdownPopperDefaultOptions);\n  });\n\n  it('assigns the default popper configuration if undefined', async () => {\n    const wrapper = mount(TDropdown, {\n      props: {\n        popperOptions: undefined,\n      },\n    });\n\n    expect(wrapper.vm.popperOptions).toEqual(TDropdownPopperDefaultOptions);\n  });\n\n  it('the dropdownAfterLeave method removes the `visibility` property', async () => {\n    const wrapper = mount(TDropdown);\n\n    const { dropdown } = wrapper.vm.$refs;\n\n    dropdown.style.visibility = 'hidden';\n\n    expect(dropdown.style.visibility).toBe('hidden');\n\n    wrapper.vm.dropdownAfterLeave();\n\n    expect(dropdown.style.visibility).toBe('');\n  });\n\n  describe('touch-only devices', () => {\n    let windowSpy: any;\n\n    beforeAll(() => {\n      windowSpy = jest.spyOn(window, 'window', 'get');\n      const windowImplementation = Object.assign(window, {\n        matchMedia: () => ({\n          matches: true,\n        }),\n      });\n\n      windowSpy.mockImplementation(() => windowImplementation);\n    });\n\n    afterAll(() => {\n      windowSpy.mockRestore();\n    });\n\n    it('detects touch only devces', () => {\n      expect(window.matchMedia('(any-hover: none)')).toEqual({\n        matches: true,\n      });\n\n      const wrapper = mount(TDropdown);\n\n      expect(wrapper.vm.isTouchOnlyDevice).toBe(true);\n    });\n\n    it('ignores mouseoverHandler action in touch-only devices', async () => {\n      const wrapper = mount(TDropdown, {\n        props: {\n          toggleOnHover: true,\n        },\n      });\n\n      wrapper.vm.isTouchOnlyDevice = true;\n\n      const action = jest.spyOn(wrapper.vm, 'doShow');\n\n      const trigger = wrapper.get('button');\n\n      await trigger.trigger('mouseover');\n\n      expect(action).not.toHaveBeenCalled();\n    });\n\n    it('ignores mouseleaveHandler action in touch-only devices', async () => {\n      const wrapper = mount(TDropdown, {\n        props: {\n          toggleOnHover: true,\n        },\n      });\n\n      wrapper.vm.isTouchOnlyDevice = true;\n\n      const action = jest.spyOn(wrapper.vm, 'targetIsChild');\n\n      const trigger = wrapper.get('button');\n\n      await trigger.trigger('mouseleave');\n\n      expect(action).not.toHaveBeenCalled();\n    });\n\n    it('ignores focusHandler action in touch-only devices', async () => {\n      const wrapper = mount(TDropdown, {\n        props: {\n          toggleOnFocus: true,\n        },\n      });\n\n      const trigger = wrapper.get('button');\n\n      await trigger.trigger('focus');\n\n      expect(wrapper.vm.shown).toBe(false);\n    });\n\n    it('ignores blurHandler action in touch-only devices', async () => {\n      const wrapper = mount(TDropdown, {\n        props: {\n          toggleOnFocus: true,\n        },\n      });\n\n      // doHide should not be called\n      const action = jest.spyOn(wrapper.vm, 'doHide');\n\n      const trigger = wrapper.get('button');\n\n      await trigger.trigger('blur');\n\n      expect(action).not.toHaveBeenCalled();\n    });\n\n    it('shows the dropdown when clicked on touch-only devices if `toggleOnFocus` is set even if `toggleOnClick` is false', async () => {\n      const wrapper = mount(TDropdown, {\n        props: {\n          toggleOnFocus: true,\n          toggleOnClick: false,\n        },\n      });\n\n      const trigger = wrapper.get('button');\n\n      await trigger.trigger('click');\n\n      expect(wrapper.vm.shown).toBe(true);\n    });\n\n    it('shows the dropdown when clicked on touch-only devices if `toggleOnHover` is set even if `toggleOnClick` is false', async () => {\n      const wrapper = mount(TDropdown, {\n        props: {\n          toggleOnHover: true,\n          toggleOnFocus: false,\n          toggleOnClick: false,\n        },\n      });\n\n      const trigger = wrapper.get('button');\n\n      await trigger.trigger('click');\n\n      expect(wrapper.vm.shown).toBe(true);\n    });\n\n    it('adds the `touchstartHandler` to the current window when dropdown is shown and is isTouchOnlyDevice', async () => {\n      const wrapper = mount(TDropdown);\n\n      const addSpy = jest.spyOn(window, 'addEventListener');\n      const removeSpy = jest.spyOn(window, 'removeEventListener');\n\n      wrapper.vm.doShow();\n\n      await wrapper.vm.$nextTick();\n\n      expect(addSpy).toHaveBeenCalledWith('touchstart', wrapper.vm.touchstartHandler);\n\n      wrapper.vm.doHide();\n\n      await wrapper.vm.$nextTick();\n\n      expect(removeSpy).toHaveBeenCalledWith('touchstart', wrapper.vm.touchstartHandler);\n    });\n\n    it('adds the `touchstartHandler` if the component is shown when mounted', async () => {\n      const addSpy = jest.spyOn(window, 'addEventListener');\n\n      const wrapper = mount(TDropdown, {\n        props: {\n          show: true,\n        },\n      });\n\n      expect(addSpy).toHaveBeenCalledWith('touchstart', wrapper.vm.touchstartHandler);\n    });\n\n    it('removes the `touchstartHandler` if the component when component is unmounted', async () => {\n      const removeSpy = jest.spyOn(window, 'removeEventListener');\n\n      const wrapper = mount(TDropdown, {\n        props: {\n          show: true,\n        },\n      });\n\n      wrapper.unmount();\n\n      expect(removeSpy).toHaveBeenCalledWith('touchstart', wrapper.vm.touchstartHandler);\n    });\n\n    it('hides the dropdown if toggle on focus is set and when touch outside', async () => {\n      const wrapper = mount(TDropdown, {\n        props: {\n          toggleOnFocus: true,\n          toggleOnClick: false,\n          show: true,\n        },\n      });\n\n      window.dispatchEvent(new TouchEvent('touchstart'));\n\n      await wrapper.vm.$nextTick();\n\n      expect(wrapper.vm.shown).toBe(false);\n    });\n\n    it('doesnt hides the dropdown if touch a children even if toggle on focus is set', async () => {\n      const wrapper = mount(TDropdown, {\n        props: {\n          toggleOnFocus: true,\n          toggleOnClick: false,\n          show: true,\n        },\n      });\n\n      window.dispatchEvent(new TouchEvent('touchstart', {\n        targetTouches: [\n          {\n            identifier: 1,\n            target: wrapper.vm.$refs.dropdown as EventTarget,\n          } as Touch,\n        ],\n      }));\n\n      await wrapper.vm.$nextTick();\n\n      expect(wrapper.vm.shown).toBe(true);\n    });\n\n    it('hides the dropdown if toggle on hover is set and when touch outside', async () => {\n      const wrapper = mount(TDropdown, {\n        props: {\n          toggleOnFocus: false,\n          toggleOnClick: false,\n          toggleOnHover: true,\n          show: true,\n        },\n      });\n\n      window.dispatchEvent(new TouchEvent('touchstart'));\n\n      await wrapper.vm.$nextTick();\n\n      expect(wrapper.vm.shown).toBe(false);\n    });\n\n    it('doesnt hides the dropdown if toggle on hover and toggle on focus is not set when touch outside', async () => {\n      const wrapper = mount(TDropdown, {\n        props: {\n          toggleOnFocus: false,\n          toggleOnClick: false,\n          toggleOnHover: false,\n          show: true,\n        },\n      });\n\n      window.dispatchEvent(new TouchEvent('touchstart'));\n\n      await wrapper.vm.$nextTick();\n\n      expect(wrapper.vm.shown).toBe(true);\n    });\n\n    it('calls the `enablePopperNeedsAdjustmentListener` when popperIsAdjusted is set', async () => {\n      const wrapper = mount(TDropdown);\n\n      const enablePopperNeedsAdjustmentListenerSpy = jest.spyOn(wrapper.vm, 'enablePopperNeedsAdjustmentListener');\n\n      wrapper.vm.popperIsAdjusted = true;\n\n      await wrapper.vm.$nextTick();\n\n      expect(enablePopperNeedsAdjustmentListenerSpy).toHaveBeenCalled();\n    });\n\n    it('calls the `disablePopperNeedsAdjustmentListener` when popperIsAdjusted is set to false', async () => {\n      const wrapper = mount(TDropdown);\n\n      const disablePopperNeedsAdjustmentListenerSpy = jest.spyOn(wrapper.vm, 'disablePopperNeedsAdjustmentListener');\n\n      wrapper.vm.popperIsAdjusted = true;\n\n      await wrapper.vm.$nextTick();\n\n      wrapper.vm.popperIsAdjusted = false;\n\n      await wrapper.vm.$nextTick();\n\n      expect(disablePopperNeedsAdjustmentListenerSpy).toHaveBeenCalled();\n    });\n\n    it('set popperIsAdjusted to false when scroll event after is adjusted', async () => {\n      jest.useFakeTimers();\n\n      const wrapper = mount(TDropdown);\n\n      wrapper.vm.popperIsAdjusted = true;\n\n      await wrapper.vm.$nextTick();\n\n      window.dispatchEvent(new Event('scroll'));\n\n      expect(wrapper.vm.popperIsAdjusted).toBe(true);\n\n      // need to wait because is throttled\n      jest.advanceTimersByTime(200);\n\n      expect(wrapper.vm.popperIsAdjusted).toBe(false);\n\n      jest.useRealTimers();\n    });\n\n    it('set popperIsAdjusted to false when resize event after is adjusted', async () => {\n      jest.useFakeTimers();\n\n      const wrapper = mount(TDropdown);\n\n      wrapper.vm.popperIsAdjusted = true;\n\n      await wrapper.vm.$nextTick();\n\n      window.dispatchEvent(new Event('resize'));\n\n      expect(wrapper.vm.popperIsAdjusted).toBe(true);\n\n      // need to wait because is throttled\n      jest.advanceTimersByTime(200);\n\n      expect(wrapper.vm.popperIsAdjusted).toBe(false);\n\n      jest.useRealTimers();\n    });\n\n    it('removes the listener to resize and scroll after component is unmounted', async () => {\n      const removeEventListenerSpy = jest.spyOn(window, 'removeEventListener');\n\n      const wrapper = mount(TDropdown);\n\n      wrapper.unmount();\n\n      expect(removeEventListenerSpy).toHaveBeenCalledWith('resize', wrapper.vm.popperAdjusterListener);\n      expect(removeEventListenerSpy).toHaveBeenCalledWith('scroll', wrapper.vm.popperAdjusterListener);\n    });\n  });\n});\n\ndescribe('TDropdown popper instance', () => {\n  const popperWasCreated = async (wrapper: VueWrapper<any>) => {\n    do {\n      // eslint-disable-next-line no-await-in-loop\n      await wrapper.vm.$nextTick();\n    } while (wrapper.vm.popper === null);\n\n    return Promise.resolve();\n  };\n\n  const popperIsAdjusted = async (wrapper: VueWrapper<any>) => {\n    do {\n      // eslint-disable-next-line no-await-in-loop\n      await wrapper.vm.$nextTick();\n    } while (wrapper.vm.popperIsAdjusted === false);\n\n    return Promise.resolve();\n  };\n\n  it('creates a popper instance when shown', async () => {\n    const wrapper = mount(TDropdown);\n\n    expect(wrapper.vm.popper).toBeNull();\n\n    wrapper.vm.doShow();\n\n    await popperWasCreated(wrapper);\n\n    expect(wrapper.vm.popper).toBeTruthy();\n\n    await popperIsAdjusted(wrapper);\n\n    expect(wrapper.vm.popperIsAdjusted).toBe(true);\n  });\n\n  it('doesnt create popper if already exists', async () => {\n    const wrapper = mount(TDropdown);\n\n    const createPopperSpy = jest.spyOn(wrapper.vm, 'createPopper');\n\n    wrapper.vm.doShow();\n\n    await popperWasCreated(wrapper);\n\n    expect(createPopperSpy).toHaveBeenCalledTimes(1);\n\n    expect(wrapper.vm.popper).toBeTruthy();\n\n    wrapper.vm.doHide();\n\n    await wrapper.vm.$nextTick();\n\n    expect(wrapper.vm.shown).toBe(false);\n\n    expect(createPopperSpy).toHaveBeenCalledTimes(1);\n  });\n\n  it('adjust popper if marked as not adjusted', async () => {\n    const wrapper = mount(TDropdown);\n\n    wrapper.vm.doShow();\n\n    await popperWasCreated(wrapper);\n\n    const popperUpdateSpy = jest.spyOn(wrapper.vm.popper, 'update');\n\n    wrapper.vm.doHide();\n\n    wrapper.vm.popperIsAdjusted = false;\n\n    wrapper.vm.doShow();\n\n    await wrapper.vm.$nextTick();\n\n    expect(popperUpdateSpy).toHaveBeenCalled();\n  });\n\n  it('doesnt adjust popper if marked as adjusted', async () => {\n    const wrapper = mount(TDropdown);\n\n    wrapper.vm.doShow();\n\n    await popperWasCreated(wrapper);\n\n    const popperUpdateSpy = jest.spyOn(wrapper.vm.popper, 'update');\n\n    wrapper.vm.doHide();\n\n    wrapper.vm.popperIsAdjusted = true;\n\n    await wrapper.vm.$nextTick();\n\n    expect(popperUpdateSpy).not.toHaveBeenCalled();\n\n    wrapper.vm.doShow();\n\n    await wrapper.vm.$nextTick();\n\n    expect(popperUpdateSpy).not.toHaveBeenCalled();\n  });\n\n  it('doesnt adjust popper if marked as adjusted (method check)', async () => {\n    const wrapper = mount(TDropdown);\n\n    wrapper.vm.doShow();\n\n    await popperWasCreated(wrapper);\n\n    const popperUpdateSpy = jest.spyOn(wrapper.vm, 'adjustPopper');\n\n    wrapper.vm.doHide();\n\n    wrapper.vm.popperIsAdjusted = true;\n\n    await wrapper.vm.$nextTick();\n\n    expect(popperUpdateSpy).not.toHaveBeenCalled();\n\n    wrapper.vm.doShow();\n\n    await wrapper.vm.$nextTick();\n\n    expect(popperUpdateSpy).not.toHaveBeenCalled();\n  });\n\n  it('doesnt adjust popper if is hidden and adjustingPopper is false', async () => {\n    const wrapper = mount(TDropdown);\n\n    // Show the dropdown to initialize popper\n    wrapper.vm.doShow();\n    await popperWasCreated(wrapper);\n    wrapper.vm.doHide();\n    await wrapper.vm.$nextTick();\n    await wrapper.vm.$nextTick();\n\n    wrapper.vm.adjustingPopper = false;\n\n    const popperUpdateSpy = jest.spyOn(wrapper.vm.popper, 'update');\n\n    await wrapper.vm.adjustPopper();\n\n    await wrapper.vm.$nextTick();\n\n    expect(popperUpdateSpy).not.toHaveBeenCalled();\n  });\n\n  it('adjust popper if is hidden but adjustingPopper is true', async () => {\n    const wrapper = mount(TDropdown);\n\n    // Show the dropdown to initialize popper\n    wrapper.vm.doShow();\n    await popperWasCreated(wrapper);\n    wrapper.vm.doHide();\n    await wrapper.vm.$nextTick();\n    await wrapper.vm.$nextTick();\n\n    wrapper.vm.adjustingPopper = true;\n\n    const popperUpdateSpy = jest.spyOn(wrapper.vm.popper, 'update');\n\n    await wrapper.vm.adjustPopper();\n\n    await wrapper.vm.$nextTick();\n\n    expect(popperUpdateSpy).toHaveBeenCalled();\n  });\n\n  it('adjust popper if not is hidden and adjustingPopper is false', async () => {\n    const wrapper = mount(TDropdown);\n\n    // Show the dropdown to initialize popper\n    wrapper.vm.doShow();\n    await popperWasCreated(wrapper);\n    await wrapper.vm.$nextTick();\n    await wrapper.vm.$nextTick();\n\n    wrapper.vm.adjustingPopper = true;\n\n    const popperUpdateSpy = jest.spyOn(wrapper.vm.popper, 'update');\n\n    await wrapper.vm.adjustPopper();\n\n    await wrapper.vm.$nextTick();\n\n    expect(popperUpdateSpy).toHaveBeenCalled();\n  });\n\n  it('accepts undefined as the placement', async () => {\n    const wrapper = mount(TDropdown, {\n      props: {\n        placement: undefined,\n      },\n    });\n\n    wrapper.vm.doShow();\n\n    await popperWasCreated(wrapper);\n\n    expect(wrapper.vm.popper).toBeTruthy();\n    expect(wrapper.vm.popper.state.placement).toBe(TDropdownPopperDefaultOptions.placement);\n  });\n\n  it('overrides the popper placement if placement is set', async () => {\n    const wrapper = mount(TDropdown, {\n      props: {\n        placement: 'top',\n      },\n    });\n\n    wrapper.vm.doShow();\n\n    await popperWasCreated(wrapper);\n\n    expect(wrapper.vm.popper).toBeTruthy();\n    expect(wrapper.vm.popper.state.placement).toBe('top');\n  });\n});\n"
  },
  {
    "path": "src/__tests/components/TInput.integration.spec.ts",
    "content": "/* eslint-disable @typescript-eslint/no-non-null-assertion */\nimport { render, fireEvent } from '@testing-library/vue';\nimport TInput from '@/components/TInput.vue';\n\ndescribe('TInput.vue', () => {\n  it('handles the v-model', async () => {\n    const { container, getByDisplayValue } = render(TInput);\n\n    const input = container.querySelector('input')!;\n\n    await fireEvent.update(input!, 'Alfonso');\n\n    getByDisplayValue('Alfonso');\n  });\n\n  it('contains the class + classes + fixedClasses', async () => {\n    const { container } = render(TInput, {\n      props: {\n        fixedClasses: 'text-red-500',\n        classes: 'border-red-500',\n        class: 'font-semibold',\n      },\n    });\n\n    const input = container.querySelector('.text-red-500.border-red-500.font-semibold');\n    expect(input).not.toBeNull();\n  });\n\n  it('adds the html attributes', async () => {\n    const { getByPlaceholderText, getByRole, getByTitle } = render(TInput, {\n      props: {\n        placeholder: 'Write something',\n        role: 'text-field',\n        title: 'my title',\n      },\n    });\n\n    getByPlaceholderText('Write something');\n\n    getByRole('text-field');\n\n    getByTitle('my title');\n  });\n\n  it('adds the classes on the variant', async () => {\n    const { container } = render(TInput, {\n      props: {\n        variants: {\n          error: {\n            classes: 'text-red-500',\n          },\n        },\n        variant: 'error',\n        classes: 'text-blue-500',\n      },\n    });\n\n    let input = container.querySelector('.text-red-500');\n    expect(input).not.toBeNull();\n\n    input = container.querySelector('.text-blue-500');\n    expect(input).toBeNull();\n  });\n\n  it('keeps the fixedClasses when using a variant', async () => {\n    const { container } = render(TInput, {\n      props: {\n        variants: {\n          error: {\n            classes: 'text-red-500',\n          },\n        },\n        variant: 'error',\n        fixedClasses: 'text-blue-500',\n      },\n    });\n\n    let input = container.querySelector('.text-red-500');\n    expect(input).not.toBeNull();\n\n    input = container.querySelector('.text-blue-500');\n    expect(input).not.toBeNull();\n  });\n\n  it('overrides the fixedClasses when using a variant', async () => {\n    const { container } = render(TInput, {\n      props: {\n        variants: {\n          error: {\n            fixedClasses: 'text-red-500',\n          },\n        },\n        variant: 'error',\n        fixedClasses: 'text-blue-500',\n      },\n    });\n\n    let input = container.querySelector('.text-red-500');\n    expect(input).not.toBeNull();\n\n    input = container.querySelector('.text-blue-500');\n    expect(input).toBeNull();\n  });\n});\n"
  },
  {
    "path": "src/__tests/components/TInput.spec.ts",
    "content": "/* eslint-disable @typescript-eslint/no-non-null-assertion */\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport { shallowMount } from '@vue/test-utils';\nimport { TInputConfig } from '@variantjs/core';\nimport TInput from '@/components/TInput.vue';\n\ndescribe('TInput.vue', () => {\n  it('renders the input', () => {\n    const wrapper = shallowMount(TInput);\n    expect(wrapper.get('input')).toBeTruthy();\n  });\n\n  it('renders the input with a default set of classes', () => {\n    const wrapper = shallowMount(TInput);\n\n    expect(wrapper.html()).toBe(`<input class=\"${TInputConfig.classes}\">`);\n  });\n\n  it('adds the value attribute', () => {\n    const wrapper = shallowMount(TInput,\n      {\n        global: {\n          provide: {\n            configuration: {\n              TInput: {\n                classes: undefined,\n              },\n            },\n          },\n        },\n        attrs: {\n          value: 'foo bar',\n        },\n      });\n\n    expect(wrapper.vm.$el.value).toBe('foo bar');\n  });\n\n  it('renders the input without attributes if no default theme', () => {\n    const wrapper = shallowMount(TInput, {\n      global: {\n        provide: {\n          configuration: {\n            TInput: {\n              classes: undefined,\n            },\n          },\n        },\n      },\n    });\n\n    expect(wrapper.html()).toBe('<input>');\n  });\n\n  it('set the props.value into the input value', () => {\n    const value = 'input value';\n    const wrapper = shallowMount(TInput, {\n      props: { modelValue: value },\n    });\n\n    expect(wrapper.vm.$el.value).toBe(value);\n  });\n\n  it('doesnt add the modelValue as attribute', () => {\n    const value = 'input value';\n    const wrapper = shallowMount(TInput, {\n      props: { modelValue: value },\n    });\n\n    expect(wrapper.vm.$el.attributes.modelValue).toBeUndefined();\n  });\n\n  it('disables the input', async () => {\n    const wrapper = shallowMount(TInput, {\n      props: { disabled: false },\n    });\n    expect(wrapper.vm.$el.disabled).toBe(false);\n\n    await wrapper.setProps({ disabled: true });\n\n    expect(wrapper.vm.$el.disabled).toBe(true);\n  });\n\n  it('has input attributes', async () => {\n    const wrapper = shallowMount(TInput);\n\n    const values = {\n      id: {\n        default: '',\n        new: 'new-id',\n      },\n      autocomplete: {\n        default: '',\n        new: 'on',\n      },\n      autofocus: {\n        default: false,\n        new: true,\n      },\n      disabled: {\n        default: false,\n        new: true,\n      },\n      max: {\n        default: '',\n        new: '10',\n      },\n      maxlength: {\n        keyName: 'maxLength',\n        default: 524288,\n        new: 12,\n      },\n      minlength: {\n        keyName: 'minLength',\n        default: 0,\n        new: 2,\n      },\n      min: {\n        default: '',\n        new: '3',\n      },\n      multiple: {\n        default: false,\n        new: true,\n      },\n      name: {\n        default: '',\n        new: 'new-name',\n      },\n      pattern: {\n        default: '',\n        new: '[A-Za-z]{3}',\n      },\n      placeholder: {\n        default: '',\n        new: 'new placeholder',\n      },\n      readonly: {\n        keyName: 'readOnly',\n        default: false,\n        new: true,\n      },\n      required: {\n        default: false,\n        new: true,\n      },\n      value: {\n        default: '',\n        new: 'my value',\n      },\n      type: {\n        default: 'text',\n        new: 'email',\n      },\n    };\n\n    const newProps: any = {};\n    // Check for the default values\n    Object.keys(values).forEach((key) => {\n      const elementValue = (values as any)[key];\n      expect(wrapper.vm.$el[elementValue.keyName || key]).toBe(elementValue.default);\n\n      newProps[key as any] = elementValue.new;\n    });\n\n    await wrapper.setProps(newProps);\n\n    // Check for the new values\n    Object.keys(values).forEach((key) => {\n      const elementValue = (values as any)[key];\n      expect(wrapper.vm.$el[elementValue.keyName || key]).toBe(elementValue.new);\n    });\n  });\n\n  it('set the model value', () => {\n    const modelValue = 'original value';\n\n    const wrapper = shallowMount(TInput, {\n      props: {\n        modelValue,\n      },\n    });\n\n    expect(wrapper.vm.$el.value).toBe(modelValue);\n  });\n\n  it('emits an update event with the input value', () => {\n    const modelValue = 'original value';\n\n    const wrapper = shallowMount(TInput, {\n      props: {\n        modelValue,\n      },\n    });\n\n    const inputValue = 'new value';\n\n    wrapper.setValue(inputValue);\n\n    expect(wrapper.emitted('update:modelValue')).toBeTruthy();\n\n    // assert event count\n    expect(wrapper.emitted('update:modelValue')?.length).toBe(1);\n\n    // assert event payload\n    expect(wrapper.emitted('update:modelValue')![0]).toEqual([inputValue]);\n  });\n\n  it('emits native input events', () => {\n    const onChange = jest.fn();\n    const onBlur = jest.fn();\n    const onFocus = jest.fn();\n    const onKeyup = jest.fn();\n    const onInput = jest.fn();\n\n    const wrapper = shallowMount(TInput, {\n      attrs: {\n        onChange,\n        onBlur,\n        onFocus,\n        onKeyup,\n        onInput,\n      },\n    });\n\n    const input = wrapper.vm.$el;\n\n    input.dispatchEvent(new Event('change'));\n    expect(onChange).toHaveBeenCalled();\n\n    input.dispatchEvent(new FocusEvent('focus'));\n    expect(onFocus).toHaveBeenCalled();\n\n    input.dispatchEvent(new FocusEvent('blur'));\n    expect(onBlur).toHaveBeenCalled();\n\n    input.dispatchEvent(new InputEvent('input'));\n    expect(onInput).toHaveBeenCalled();\n\n    input.dispatchEvent(new KeyboardEvent('keyup', { key: 'a' }));\n    expect(onKeyup).toHaveBeenCalled();\n  });\n\n  it('has native input methods', () => {\n    const wrapper = shallowMount(TInput);\n\n    const input = wrapper.vm.$el;\n\n    expect(typeof input.click).toBe('function');\n    expect(typeof input.select).toBe('function');\n    expect(typeof input.setSelectionRange).toBe('function');\n    expect(typeof input.setRangeText).toBe('function');\n  });\n\n  it('triggers custom events', async () => {\n    const onCustom = jest.fn();\n\n    const wrapper = shallowMount(TInput, {\n      attrs: {\n        onCustom,\n      },\n    });\n    const input = wrapper.vm.$el as HTMLInputElement;\n\n    const evt = new CustomEvent('custom', { detail: 'my-custom-event' });\n    input.dispatchEvent(evt);\n\n    expect(onCustom).toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "src/__tests/components/TInputGroup.spec.ts",
    "content": "import { shallowMount } from '@vue/test-utils';\nimport { TInputGroupConfig } from '@variantjs/core';\nimport TInputGroup from '@/components/TInputGroup.vue';\n\ndescribe('TInputGroup.vue', () => {\n  it('renders the component without errors', () => {\n    const wrapper = shallowMount(TInputGroup);\n    expect(wrapper.vm.$el.tagName).toBe('DIV');\n  });\n\n  it('adds the elements in default order', () => {\n    const wrapper = shallowMount(TInputGroup, {\n      props: {\n        label: 'the label',\n        feedback: 'the feedback',\n        description: 'the description',\n      },\n      slots: {\n        default: 'the body',\n      },\n    });\n\n    const els = wrapper.vm.$el.children;\n    const label = els[0];\n    const body = els[1];\n    const feedback = els[2];\n    const description = els[3];\n\n    expect(els.length).toBe(4);\n    expect(label.innerHTML).toBe('the label');\n    expect(body.innerHTML).toBe('the body');\n    expect(feedback.innerHTML).toBe('the feedback');\n    expect(description.innerHTML).toBe('the description');\n  });\n\n  it('adds the elements from the slots', () => {\n    const wrapper = shallowMount(TInputGroup, {\n      slots: {\n        default: 'the body',\n        label: 'the label',\n        feedback: 'the feedback',\n        description: 'the description',\n      },\n    });\n\n    const els = wrapper.vm.$el.children;\n    const label = els[0];\n    const body = els[1];\n    const feedback = els[2];\n    const description = els[3];\n\n    expect(els.length).toBe(4);\n    expect(label.innerHTML).toBe('the label');\n    expect(body.innerHTML).toBe('the body');\n    expect(feedback.innerHTML).toBe('the feedback');\n    expect(description.innerHTML).toBe('the description');\n  });\n\n  it('doesnt add empty elements', () => {\n    const wrapper = shallowMount(TInputGroup, {\n      props: {\n        label: 'the label',\n      },\n      slots: {\n        default: 'the body',\n      },\n    });\n\n    const els = wrapper.vm.$el.children;\n    const label = els[0];\n    const body = els[1];\n\n    expect(els.length).toBe(2);\n    expect(label.innerHTML).toBe('the label');\n    expect(body.innerHTML).toBe('the body');\n  });\n\n  it('adds only the elements defined on the sortedElements prop', () => {\n    const wrapper = shallowMount(TInputGroup, {\n      props: {\n        sortedElements: [\n          'label', 'description',\n        ],\n        label: 'the label',\n        feedback: 'the feedback',\n        description: 'the description',\n      },\n      slots: {\n        default: 'the body',\n      },\n    });\n\n    const els = wrapper.vm.$el.children;\n    const label = els[0];\n    const description = els[1];\n\n    expect(els.length).toBe(2);\n    expect(label.innerHTML).toBe('the label');\n    expect(description.innerHTML).toBe('the description');\n  });\n\n  it('adds the elements in different order', () => {\n    const wrapper = shallowMount(TInputGroup, {\n      props: {\n        sortedElements: [\n          'feedback', 'description', 'label', 'default',\n        ],\n        label: 'the label',\n        feedback: 'the feedback',\n        description: 'the description',\n      },\n      slots: {\n        default: 'the body',\n      },\n    });\n\n    const els = wrapper.vm.$el.children;\n    const feedback = els[0];\n    const description = els[1];\n    const label = els[2];\n    const body = els[3];\n\n    expect(els.length).toBe(4);\n    expect(label.innerHTML).toBe('the label');\n    expect(body.innerHTML).toBe('the body');\n    expect(feedback.innerHTML).toBe('the feedback');\n    expect(description.innerHTML).toBe('the description');\n  });\n\n  it('prioritizes the slots over the props', () => {\n    const wrapper = shallowMount(TInputGroup, {\n      props: {\n        body: 'not',\n        label: 'not',\n        feedback: 'not',\n        description: 'not',\n      },\n      slots: {\n        default: 'the body',\n        label: 'the label',\n        feedback: 'the feedback',\n        description: 'the description',\n      },\n    });\n\n    const els = wrapper.vm.$el.children;\n    const label = els[0];\n    const body = els[1];\n    const feedback = els[2];\n    const description = els[3];\n\n    expect(els.length).toBe(4);\n    expect(label.innerHTML).toBe('the label');\n    expect(body.innerHTML).toBe('the body');\n    expect(feedback.innerHTML).toBe('the feedback');\n    expect(description.innerHTML).toBe('the description');\n  });\n\n  it('adds the text on the body props to the default slot', () => {\n    const wrapper = shallowMount(TInputGroup, {\n      props: {\n        body: 'from the prop',\n      },\n    });\n\n    const els = wrapper.vm.$el.children;\n    const body = els[0];\n\n    expect(els.length).toBe(1);\n    expect(body.innerHTML).toBe('from the prop');\n  });\n\n  it('uses default tagNames for elements', () => {\n    const wrapper = shallowMount(TInputGroup, {\n      slots: {\n        default: 'the body',\n        label: 'the label',\n        feedback: 'the feedback',\n        description: 'the description',\n      },\n    });\n\n    const els = wrapper.vm.$el.children;\n    const label = els[0];\n    const body = els[1];\n    const feedback = els[2];\n    const description = els[3];\n\n    expect(label.tagName).toBe('LABEL');\n    expect(body.tagName).toBe('DIV');\n    expect(feedback.tagName).toBe('DIV');\n    expect(description.tagName).toBe('DIV');\n  });\n\n  it('accepts different tagNames for elements', () => {\n    const wrapper = shallowMount(TInputGroup, {\n      props: {\n        tagName: 'fieldset',\n        bodyTagName: 'table',\n        labelTagName: 'span',\n        feedbackTagName: 'a',\n        descriptionTagName: 'p',\n      },\n      slots: {\n        default: 'the body',\n        label: 'the label',\n        feedback: 'the feedback',\n        description: 'the description',\n      },\n    });\n\n    const wrap = wrapper.vm.$el;\n    const els = wrap.children;\n    const label = els[0];\n    const body = els[1];\n    const feedback = els[2];\n    const description = els[3];\n\n    expect(wrap.tagName).toBe('FIELDSET');\n    expect(label.tagName).toBe('SPAN');\n    expect(body.tagName).toBe('TABLE');\n    expect(feedback.tagName).toBe('A');\n    expect(description.tagName).toBe('P');\n  });\n\n  it('uses a `div` for the element', () => {\n    const wrapper = shallowMount(TInputGroup, {\n      props: {\n        label: 'im a label',\n      },\n    });\n\n    expect(wrapper.vm.$el.children[0].tagName).toBe('LABEL');\n  });\n\n  it('has a default theme', () => {\n    const wrapper = shallowMount(TInputGroup, {\n      slots: {\n        default: 'the body',\n        label: 'the label',\n        feedback: 'the feedback',\n        description: 'the description',\n      },\n    });\n\n    const wrap = wrapper.vm.$el;\n    const els = wrapper.vm.$el.children;\n    const label = els[0];\n    const body = els[1];\n    const feedback = els[2];\n    const description = els[3];\n\n    expect(wrap.className).toBe(TInputGroupConfig.classes.wrapper);\n    expect(label.className).toBe(TInputGroupConfig.classes.label);\n    expect(body.className).toBe(TInputGroupConfig.classes.body);\n    expect(feedback.className).toBe(TInputGroupConfig.classes.feedback);\n    expect(description.className).toBe(TInputGroupConfig.classes.description);\n  });\n\n  it('adds html attributes', () => {\n    const wrapper = shallowMount(TInputGroup, {\n      attrs: {\n        id: 'my-id',\n      },\n    });\n\n    const wrap = wrapper.vm.$el as HTMLDivElement;\n\n    expect(wrap.getAttribute('id')).toBe('my-id');\n  });\n\n  it('adds attributes from global configuration', () => {\n    const wrapper = shallowMount(TInputGroup, {\n      global: {\n        provide: {\n          configuration: {\n            TInputGroup: {\n              id: 'my-id',\n            },\n          },\n        },\n      },\n    });\n\n    const wrap = wrapper.vm.$el as HTMLDivElement;\n\n    expect(wrap.getAttribute('id')).toBe('my-id');\n  });\n\n  it('used the props from global configuration', () => {\n    const wrapper = shallowMount(TInputGroup, {\n      global: {\n        provide: {\n          configuration: {\n            TInputGroup: {\n              description: 'hello hello',\n            },\n          },\n        },\n      },\n    });\n\n    expect(wrapper.vm.$el.querySelector('div').innerHTML).toBe('hello hello');\n  });\n});\n"
  },
  {
    "path": "src/__tests/components/TModal.spec.ts",
    "content": "/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { shallowMount, mount } from '@vue/test-utils';\nimport * as bodyScrollLockModule from 'body-scroll-lock';\nimport { TModalConfig } from '@variantjs/core';\nimport TModal from '@/components/TModal.vue';\nimport plugin from '../../plugin';\n\nconst waitUntilModalIsVisible = (wrapper: any) : Promise<void> => new Promise((resolve) => {\n  // 1. Component is added to the DOM\n  wrapper.vm.$nextTick().then(() => {\n    // 2. Overlay is about to show\n    wrapper.vm.$nextTick().then(() => {\n      // 3. Overlay is shown, modal is about to show\n      wrapper.vm.$nextTick().then(() => {\n        // 4 Modal is shown\n        wrapper.vm.$nextTick().then(() => {\n          resolve();\n        });\n      });\n    });\n  });\n});\n\ndescribe('TModal.vue', () => {\n  it('doesnt show the component by default', () => {\n    const wrapper = shallowMount(TModal);\n    expect(wrapper.vm.$el.tagName).toBeUndefined();\n  });\n\n  describe('opening modal', () => {\n    const props = {\n      teleport: false,\n    };\n\n    describe('with the `show` method', () => {\n      it('show the component when calling the show method', async () => {\n        const wrapper = mount(TModal, {\n          props,\n        });\n\n        expect(wrapper.vm.showComponent).toBe(false);\n\n        wrapper.vm.show();\n\n        await wrapper.vm.$nextTick();\n\n        expect(wrapper.vm.showComponent).toBe(true);\n      });\n\n      it('pass parameters from the show method to the before-show event', async () => {\n        const wrapper = mount(TModal, {\n          props,\n        });\n\n        const params = {\n          foo: 'bar',\n        };\n\n        expect(wrapper.vm.showComponent).toBe(false);\n\n        wrapper.vm.show(params);\n\n        await wrapper.vm.$nextTick();\n\n        expect(wrapper.vm.showComponent).toBe(true);\n\n        expect((wrapper.emitted('before-show')![0] as any)[0].params).toEqual(params);\n      });\n\n      it('cancel the show if the cancel method is called', async () => {\n        const wrapper = mount(TModal, {\n          props: {\n            ...props,\n          },\n        });\n\n        const emitSpy = jest.spyOn(wrapper.vm.$, 'emit').mockImplementation((name, ...params) => {\n          if (name === 'before-show') {\n            (params as any).cancel();\n          }\n        });\n\n        wrapper.vm.show();\n\n        await wrapper.vm.$nextTick();\n\n        expect(wrapper.vm.showComponent).toBe(false);\n\n        emitSpy.mockRestore();\n      });\n    });\n\n    describe('with the $modal global property', () => {\n      it('show the component when calling the show method', async () => {\n        const wrapper = mount(TModal, {\n          props: {\n            ...props,\n            name: 'modal-name',\n          },\n          global: {\n            plugins: [plugin],\n          },\n        });\n\n        expect(wrapper.vm.showComponent).toBe(false);\n\n        wrapper.vm.$modal.show('modal-name');\n\n        await wrapper.vm.$nextTick();\n\n        expect(wrapper.vm.showComponent).toBe(true);\n      });\n\n      it('doesnt show the component when calling the show method if different name', async () => {\n        const wrapper = mount(TModal, {\n          props: {\n            ...props,\n            name: 'other-name',\n          },\n          global: {\n            plugins: [plugin],\n          },\n        });\n\n        expect(wrapper.vm.showComponent).toBe(false);\n\n        wrapper.vm.$modal.show('modal-name');\n\n        await wrapper.vm.$nextTick();\n\n        expect(wrapper.vm.showComponent).toBe(false);\n      });\n\n      it('pass parameters from the show method to the before-show event', async () => {\n        const wrapper = mount(TModal, {\n          props: {\n            ...props,\n            name: 'modal-name',\n          },\n          global: {\n            plugins: [plugin],\n          },\n        });\n\n        const params = {\n          foo: 'bar',\n        };\n\n        expect(wrapper.vm.showComponent).toBe(false);\n\n        wrapper.vm.$modal.show('modal-name', params);\n\n        await wrapper.vm.$nextTick();\n\n        expect(wrapper.vm.showComponent).toBe(true);\n\n        expect((wrapper.emitted('before-show')![0] as any)[0].params).toEqual(params);\n      });\n\n      it('cancel the show if the cancel method is called', async () => {\n        const wrapper = mount(TModal, {\n          props: {\n            ...props,\n            name: 'modal-name',\n          },\n          global: {\n            plugins: [plugin],\n          },\n        });\n\n        const emitSpy = jest.spyOn(wrapper.vm.$, 'emit').mockImplementation((name, ...params) => {\n          if (name === 'before-show') {\n            (params as any).cancel();\n          }\n        });\n\n        wrapper.vm.$modal.show('modal-name');\n\n        await wrapper.vm.$nextTick();\n\n        expect(wrapper.vm.showComponent).toBe(false);\n\n        emitSpy.mockRestore();\n      });\n    });\n\n    describe('with the vModel', () => {\n      it('show the component when updated the v-model to true', async () => {\n        const wrapper = mount(TModal, {\n          props,\n        });\n\n        expect(wrapper.vm.showComponent).toBe(false);\n\n        wrapper.setProps({\n          modelValue: true,\n        });\n\n        await wrapper.vm.$nextTick();\n\n        expect(wrapper.vm.showComponent).toBe(true);\n      });\n    });\n  });\n\n  describe('hiding modal', () => {\n    const props = {\n      teleport: false,\n      modelValue: true,\n    };\n\n    describe('with the `hide` method', () => {\n      it('hides the component when calling the hide method', async () => {\n        const wrapper = mount(TModal, {\n          props,\n        });\n\n        expect(wrapper.vm.showModal).toBe(true);\n\n        wrapper.vm.hide();\n\n        await wrapper.vm.$nextTick();\n\n        expect(wrapper.vm.showModal).toBe(false);\n      });\n\n      it('cancel the hide if the cancel method is called', async () => {\n        const wrapper = mount(TModal, {\n          props,\n        });\n\n        const emitSpy = jest.spyOn(wrapper.vm.$, 'emit').mockImplementation((name, ...params) => {\n          if (name === 'before-hide') {\n            (params as any).cancel();\n          }\n        });\n\n        wrapper.vm.hide();\n\n        await wrapper.vm.$nextTick();\n\n        expect(wrapper.vm.showModal).toBe(true);\n\n        emitSpy.mockRestore();\n      });\n    });\n\n    describe('with the $modal global property', () => {\n      it('show the component when calling the show method', async () => {\n        const wrapper = mount(TModal, {\n          props: {\n            ...props,\n            name: 'modal-name',\n          },\n          global: {\n            plugins: [plugin],\n          },\n        });\n\n        expect(wrapper.vm.showModal).toBe(true);\n\n        wrapper.vm.$modal.hide('modal-name');\n\n        await wrapper.vm.$nextTick();\n\n        expect(wrapper.vm.showModal).toBe(false);\n      });\n\n      it('doesnt show the component when calling the show method if different name', async () => {\n        const wrapper = mount(TModal, {\n          props: {\n            ...props,\n            name: 'other-name',\n          },\n          global: {\n            plugins: [plugin],\n          },\n        });\n\n        expect(wrapper.vm.showModal).toBe(true);\n\n        wrapper.vm.$modal.hide('modal-name');\n\n        await wrapper.vm.$nextTick();\n\n        expect(wrapper.vm.showModal).toBe(true);\n      });\n\n      it('cancel the show if the cancel method is called', async () => {\n        const wrapper = mount(TModal, {\n          props: {\n            ...props,\n            name: 'modal-name',\n          },\n          global: {\n            plugins: [plugin],\n          },\n        });\n\n        const emitSpy = jest.spyOn(wrapper.vm.$, 'emit').mockImplementation((name, ...params) => {\n          if (name === 'before-hide') {\n            (params as any).cancel();\n          }\n        });\n\n        wrapper.vm.$modal.hide('modal-name');\n\n        await wrapper.vm.$nextTick();\n\n        expect(wrapper.vm.showModal).toBe(true);\n\n        emitSpy.mockRestore();\n      });\n    });\n\n    describe('with the vModel', () => {\n      it('hides the component when updated the v-model to false', async () => {\n        const wrapper = mount(TModal, {\n          props,\n        });\n\n        expect(wrapper.vm.showModal).toBe(true);\n\n        wrapper.setProps({\n          modelValue: false,\n        });\n\n        await wrapper.vm.$nextTick();\n\n        expect(wrapper.vm.showModal).toBe(false);\n      });\n    });\n  });\n\n  describe('modal is shown initially', () => {\n    const props = {\n      modelValue: true,\n      teleport: false,\n    };\n\n    it('show the component if modelValue is set to `true`', () => {\n      const wrapper = mount(TModal, {\n        props,\n        slots: {\n          default: 'Hello World',\n        },\n      });\n\n      expect(wrapper.html()).toContain('Hello World');\n    });\n\n    describe('disable body scroll', () => {\n      it('disables the body scroll', () => {\n        const disableBodyScrollSpy = jest.spyOn(bodyScrollLockModule, 'disableBodyScroll');\n\n        mount(TModal, {\n          props,\n        });\n\n        expect(disableBodyScrollSpy).toHaveBeenCalled();\n\n        disableBodyScrollSpy.mockRestore();\n      });\n\n      it('doesnt disabled the body scroll if `disableBodyScroll` is set to `false`', () => {\n        const disableBodyScrollSpy = jest.spyOn(bodyScrollLockModule, 'disableBodyScroll');\n\n        mount(TModal, {\n          props: {\n            ...props,\n            disableBodyScroll: false,\n          },\n        });\n\n        expect(disableBodyScrollSpy).not.toHaveBeenCalled();\n\n        disableBodyScrollSpy.mockRestore();\n      });\n    });\n\n    describe('enable body scroll', () => {\n      it('enables body scroll when unmounted', () => {\n        const enableBodyScrollSpy = jest.spyOn(bodyScrollLockModule, 'enableBodyScroll');\n\n        const wrapper = mount(TModal, {\n          props,\n        });\n\n        wrapper.unmount();\n\n        expect(enableBodyScrollSpy).toHaveBeenCalled();\n\n        enableBodyScrollSpy.mockRestore();\n      });\n\n      it('doesnt enables body scroll when unmounted if `disableBodyScroll` is set to `false`', () => {\n        const enableBodyScrollSpy = jest.spyOn(bodyScrollLockModule, 'enableBodyScroll');\n\n        const wrapper = mount(TModal, {\n          props: {\n            ...props,\n            disableBodyScroll: false,\n          },\n        });\n\n        wrapper.unmount();\n\n        expect(enableBodyScrollSpy).not.toHaveBeenCalled();\n\n        enableBodyScrollSpy.mockRestore();\n      });\n\n      it('enables body scroll when modal is closed', async () => {\n        const enableBodyScrollSpy = jest.spyOn(bodyScrollLockModule, 'enableBodyScroll');\n\n        const wrapper = mount(TModal, {\n          props,\n        });\n\n        wrapper.vm.hide();\n\n        // Whole close lifecycle\n        await wrapper.vm.$nextTick();\n        await wrapper.vm.$nextTick();\n        await wrapper.vm.$nextTick();\n        await wrapper.vm.$nextTick();\n\n        expect(enableBodyScrollSpy).toHaveBeenCalled();\n\n        enableBodyScrollSpy.mockRestore();\n      });\n\n      it('doesnt enables body scroll when modal is closed if `disableBodyScroll` is set to `false`', async () => {\n        const enableBodyScrollSpy = jest.spyOn(bodyScrollLockModule, 'enableBodyScroll');\n\n        const wrapper = mount(TModal, {\n          props: {\n            ...props,\n            disableBodyScroll: false,\n          },\n        });\n\n        wrapper.vm.hide();\n\n        // Whole close lifecycle\n        await wrapper.vm.$nextTick();\n        await wrapper.vm.$nextTick();\n        await wrapper.vm.$nextTick();\n        await wrapper.vm.$nextTick();\n\n        expect(enableBodyScrollSpy).not.toHaveBeenCalled();\n\n        enableBodyScrollSpy.mockRestore();\n      });\n    });\n\n    describe('focus overlay', () => {\n      it('focus the overlay', () => {\n        const focusSpy = jest.spyOn(HTMLElement.prototype, 'focus');\n\n        mount(TModal, {\n          props,\n        });\n\n        expect(focusSpy).toHaveBeenCalled();\n\n        focusSpy.mockRestore();\n      });\n\n      it('doesnt focus the overlay if `focusOnOpen` is set to `false`', () => {\n        const focusSpy = jest.spyOn(HTMLElement.prototype, 'focus');\n\n        mount(TModal, {\n          props: {\n            ...props,\n            focusOnOpen: false,\n          },\n        });\n\n        expect(focusSpy).not.toHaveBeenCalled();\n\n        focusSpy.mockRestore();\n      });\n    });\n\n    it('emits the hide-related events in order', async () => {\n      const wrapper = mount(TModal, {\n        props,\n      });\n\n      expect(wrapper.emitted('before-hide')).toBeFalsy();\n      expect(wrapper.emitted('hidden')).toBeFalsy();\n\n      wrapper.vm.hide();\n\n      // After press hidden it just change the modelValue, no events yet\n      expect(wrapper.emitted('before-hide')).toBeFalsy();\n      expect(wrapper.emitted('hidden')).toBeFalsy();\n\n      // Model is about to hide\n      await wrapper.vm.$nextTick();\n      expect(wrapper.emitted('before-hide')).toBeTruthy();\n      expect(Object.keys((wrapper.emitted('before-hide')![0] as any)[0])).toEqual([\n        'cancel',\n        'reason',\n      ]);\n      expect(wrapper.emitted('hidden')).toBeFalsy();\n\n      // Modal is hidden, overlay is about to hide (no new events emitted)\n      await wrapper.vm.$nextTick();\n      expect(wrapper.emitted('before-hide')).toBeTruthy();\n      expect(wrapper.emitted('hidden')).toBeFalsy();\n\n      // Overlay is hidden, component is about to be removed from the DOM (no new events emitted)\n      await wrapper.vm.$nextTick();\n      expect(wrapper.emitted('before-hide')).toBeTruthy();\n      expect(wrapper.emitted('hidden')).toBeFalsy();\n\n      // component is removed from the DOM\n      await wrapper.vm.$nextTick();\n      expect(wrapper.emitted('before-hide')).toBeTruthy();\n      expect(wrapper.emitted('hidden')).toBeTruthy();\n    });\n\n    describe('press esc key', () => {\n      it('hides the modal when press esc', async () => {\n        const wrapper = mount(TModal, {\n          props,\n        });\n\n        wrapper.vm.$refs.overlay.dispatchEvent(new KeyboardEvent('keydown', {\n          key: 'Escape',\n        }));\n\n        await wrapper.vm.$nextTick();\n\n        // Meaning the modal was hidden\n        expect(wrapper.vm.$.setupState.showModal).toBe(false);\n      });\n\n      it('doesnt hide the modal when press esc if `escToClose` is set to `false`', async () => {\n        const wrapper = mount(TModal, {\n          props: {\n            ...props,\n            escToClose: false,\n          },\n        });\n\n        wrapper.vm.$refs.overlay.dispatchEvent(new KeyboardEvent('keydown', {\n          key: 'Escape',\n        }));\n\n        await wrapper.vm.$nextTick();\n\n        // Meaning the modal was hidden\n        expect(wrapper.vm.$.setupState.showModal).toBe(true);\n      });\n    });\n\n    describe('user clicks the overlay (outside)', () => {\n      it('hides the modal when clicks outside', async () => {\n        const wrapper = mount(TModal, {\n          props,\n        });\n\n        wrapper.vm.$refs.overlay.dispatchEvent(new MouseEvent('click'));\n\n        await wrapper.vm.$nextTick();\n\n        // Meaning the modal was hidden\n        expect(wrapper.vm.$.setupState.showModal).toBe(false);\n      });\n\n      it('doesnt hides the modal when clicks the modal', async () => {\n        const wrapper = mount(TModal, {\n          props,\n        });\n\n        wrapper.vm.$refs.modal.dispatchEvent(new MouseEvent('click'));\n\n        await wrapper.vm.$nextTick();\n\n        // Meaning the modal was hidden\n        expect(wrapper.vm.$.setupState.showModal).toBe(true);\n      });\n\n      it('doesnt hide the modal when click outside if `clickToClose` is set to `false`', async () => {\n        const wrapper = mount(TModal, {\n          props: {\n            ...props,\n            clickToClose: false,\n          },\n        });\n\n        wrapper.vm.$refs.overlay.dispatchEvent(new MouseEvent('click'));\n\n        await wrapper.vm.$nextTick();\n\n        // Meaning the modal was hidden\n        expect(wrapper.vm.$.setupState.showModal).toBe(true);\n      });\n    });\n  });\n\n  describe('modal is hidden initially', () => {\n    const props = {\n      teleport: false,\n    };\n\n    it('focus the overlay when shown', async () => {\n      const focusSpy = jest.spyOn(HTMLElement.prototype, 'focus');\n\n      const wrapper = mount(TModal, {\n        props,\n      });\n\n      expect(focusSpy).not.toHaveBeenCalled();\n\n      wrapper.vm.show();\n\n      await waitUntilModalIsVisible(wrapper);\n\n      expect(focusSpy).toHaveBeenCalled();\n\n      focusSpy.mockRestore();\n    });\n\n    it('emits the open-related events in order', async () => {\n      const wrapper = mount(TModal, {\n        props,\n      });\n\n      expect(wrapper.emitted('before-show')).toBeFalsy();\n      expect(wrapper.emitted('shown')).toBeFalsy();\n\n      wrapper.vm.show();\n\n      // After press shown it just adds the component into the DOM, no events emitted yet\n      expect(wrapper.emitted('before-show')).toBeFalsy();\n      expect(wrapper.emitted('shown')).toBeFalsy();\n\n      // Component is added to the DOM, but not shown yet\n      await wrapper.vm.$nextTick();\n      expect(wrapper.emitted('before-show')).toBeTruthy();\n      expect(Object.keys((wrapper.emitted('before-show')![0] as any)[0])).toEqual([\n        'cancel',\n        'params',\n      ]);\n      expect(wrapper.emitted('shown')).toBeFalsy();\n\n      // Overlay is about to show (no new events emitted)\n      await wrapper.vm.$nextTick();\n      expect(wrapper.emitted('before-show')).toBeTruthy();\n      expect(wrapper.emitted('shown')).toBeFalsy();\n\n      // Overlay is shown, modal is about to show (no new events emitted)\n      await wrapper.vm.$nextTick();\n      expect(wrapper.emitted('before-show')).toBeTruthy();\n      expect(wrapper.emitted('shown')).toBeFalsy();\n\n      // Modal is shown\n      await wrapper.vm.$nextTick();\n      expect(wrapper.emitted('before-show')).toBeTruthy();\n      expect(wrapper.emitted('shown')).toBeTruthy();\n    });\n  });\n\n  describe('classes', () => {\n    const props = {\n      teleport: false,\n    };\n\n    it('creates the overlayTransitionClassesList computed property from default configuration', () => {\n      const wrapper = mount(TModal, {\n        props,\n      });\n\n      expect(wrapper.vm.overlayTransitionClassesList).toEqual({\n        enterActiveClass: TModalConfig.classes.overlayEnterActiveClass,\n        enterFromClass: TModalConfig.classes.overlayEnterFromClass,\n        enterToClass: TModalConfig.classes.overlayEnterToClass,\n        leaveActiveClass: TModalConfig.classes.overlayLeaveActiveClass,\n        leaveFromClass: TModalConfig.classes.overlayLeaveFromClass,\n        leaveToClass: TModalConfig.classes.overlayLeaveToClass,\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "src/__tests/components/TRadio.integration.spec.ts",
    "content": "/* eslint-disable @typescript-eslint/no-non-null-assertion */\nimport { render, fireEvent } from '@testing-library/vue';\nimport TRadio from '@/components/TRadio.vue';\n\ndescribe('TRadio.vue', () => {\n  it('handles the v-model', async () => {\n    const modelValue = 'A';\n    const { container } = render(TRadio, {\n      props: {\n        modelValue,\n      },\n      attrs: {\n        name: 'radio-input',\n        value: 'A',\n      },\n    });\n    const { container: container2 } = render(TRadio, {\n      props: {\n        modelValue,\n      },\n      attrs: {\n        name: 'radio-input',\n        value: 'B',\n      },\n    });\n\n    const input = container.querySelector('input')!;\n    const input2 = container2.querySelector('input')!;\n\n    expect(input.checked).toBe(true);\n    expect(input2.checked).toBe(false);\n\n    await fireEvent.update(input2!, 'B');\n\n    expect(input.checked).toBe(false);\n    expect(input2.checked).toBe(true);\n  });\n\n  it('handles the v-model with not regular value types', async () => {\n    const modelValue = [123, 'A'];\n    const { container } = render(TRadio, {\n      props: {\n        modelValue,\n      },\n      attrs: {\n        name: 'radio-input',\n        value: modelValue,\n      },\n    });\n    const { container: container2 } = render(TRadio, {\n      props: {\n        modelValue,\n      },\n      attrs: {\n        name: 'radio-input',\n        value: () => {},\n      },\n    });\n    const { container: container3 } = render(TRadio, {\n      props: {\n        modelValue,\n      },\n      attrs: {\n        name: 'radio-input',\n        value: { A: 'B' },\n      },\n    });\n\n    const input = container.querySelector('input')!;\n    const input2 = container2.querySelector('input')!;\n    const input3 = container3.querySelector('input')!;\n\n    expect(input.checked).toBe(true);\n    expect(input2.checked).toBe(false);\n    expect(input3.checked).toBe(false);\n\n    await fireEvent.update(input2!);\n\n    expect(input.checked).toBe(false);\n    expect(input2.checked).toBe(true);\n    expect(input3.checked).toBe(false);\n\n    await fireEvent.update(input3!);\n\n    expect(input.checked).toBe(false);\n    expect(input2.checked).toBe(false);\n    expect(input3.checked).toBe(true);\n  });\n\n  it('handles the v-model independently if radio name is different', async () => {\n    const modelValue = 'A';\n    const { container } = render(TRadio, {\n      props: {\n        modelValue,\n      },\n      attrs: {\n        name: 'radio-input',\n        value: 'A',\n      },\n    });\n    const { container: container2 } = render(TRadio, {\n      props: {\n        modelValue,\n      },\n      attrs: {\n        name: 'radio-input-b',\n        value: 'B',\n      },\n    });\n\n    const input = container.querySelector('input')!;\n    const input2 = container2.querySelector('input')!;\n\n    expect(input.checked).toBe(true);\n    expect(input2.checked).toBe(false);\n\n    await fireEvent.update(input2!, 'B');\n\n    expect(input.checked).toBe(true);\n    expect(input2.checked).toBe(true);\n  });\n});\n"
  },
  {
    "path": "src/__tests/components/TRadio.spec.ts",
    "content": "/* eslint-disable @typescript-eslint/no-non-null-assertion */\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport { shallowMount } from '@vue/test-utils';\nimport { TRadioConfig } from '@variantjs/core';\nimport TRadio from '@/components/TRadio.vue';\n\ndescribe('TRadio.vue', () => {\n  it('renders the input', () => {\n    const wrapper = shallowMount(TRadio);\n    expect(wrapper.get('input')).toBeTruthy();\n  });\n\n  it('renders the radio input with a default set of classes', () => {\n    const wrapper = shallowMount(TRadio);\n\n    expect(wrapper.html()).toBe(`<input type=\"radio\" class=\"${TRadioConfig.classes}\">`);\n  });\n\n  it('renders the input without attributes if no default theme', () => {\n    const wrapper = shallowMount(TRadio, {\n      global: {\n        provide: {\n          configuration: {\n            TRadio: {\n              classes: undefined,\n            },\n          },\n        },\n      },\n    });\n\n    expect(wrapper.html()).toBe('<input type=\"radio\">');\n  });\n\n  it('adds the value attribute', () => {\n    const value = 'input value';\n    const wrapper = shallowMount(TRadio, {\n      attrs: { value },\n    });\n\n    expect(wrapper.vm.$el.value).toBe(value);\n  });\n\n  it('doesnt add the modelValue as attribute', () => {\n    const value = 'input value';\n    const wrapper = shallowMount(TRadio, {\n      props: { modelValue: value },\n      attrs: { value },\n    });\n\n    expect(wrapper.vm.$el.attributes.modelValue).toBeUndefined();\n  });\n\n  it('set as checked if model value is same as value', async () => {\n    const value = 'input value';\n    const wrapper = shallowMount(TRadio, {\n      props: { modelValue: 'something else' },\n      attrs: { value },\n    });\n\n    const radio = wrapper.vm.$el as HTMLInputElement;\n    expect(radio.value).toBe(value);\n    expect(radio.checked).toBe(false);\n\n    await wrapper.setProps({\n      modelValue: value,\n    });\n\n    expect(radio.value).toBe(value);\n    expect(radio.checked).toBe(true);\n  });\n\n  it('disables the input', async () => {\n    const wrapper = shallowMount(TRadio, {\n      props: { disabled: false },\n    });\n    expect(wrapper.vm.$el.disabled).toBe(false);\n\n    await wrapper.setProps({ disabled: true });\n\n    expect(wrapper.vm.$el.disabled).toBe(true);\n  });\n\n  it('accepts misc input attributes', async () => {\n    const wrapper = shallowMount(TRadio);\n\n    const values = {\n      id: {\n        default: '',\n        new: 'new-id',\n      },\n      autocomplete: {\n        default: '',\n        new: 'on',\n      },\n      autofocus: {\n        default: false,\n        new: true,\n      },\n      disabled: {\n        default: false,\n        new: true,\n      },\n      max: {\n        default: '',\n        new: '10',\n      },\n      maxlength: {\n        keyName: 'maxLength',\n        default: 524288,\n        new: 12,\n      },\n      minlength: {\n        keyName: 'minLength',\n        default: 0,\n        new: 2,\n      },\n      min: {\n        default: '',\n        new: '3',\n      },\n      multiple: {\n        default: false,\n        new: true,\n      },\n      name: {\n        default: '',\n        new: 'new-name',\n      },\n      pattern: {\n        default: '',\n        new: '[A-Za-z]{3}',\n      },\n      placeholder: {\n        default: '',\n        new: 'new placeholder',\n      },\n      readonly: {\n        keyName: 'readOnly',\n        default: false,\n        new: true,\n      },\n      required: {\n        default: false,\n        new: true,\n      },\n    };\n\n    const netProps: any = {};\n    // Check for the default values\n    Object.keys(values).forEach((key) => {\n      const elementValue = (values as any)[key];\n      expect(wrapper.vm.$el[elementValue.keyName || key]).toBe(elementValue.default);\n\n      netProps[key as any] = elementValue.new;\n    });\n\n    await wrapper.setProps(netProps);\n\n    // Check for the new values\n    Object.keys(values).forEach((key) => {\n      const elementValue = (values as any)[key];\n      expect(wrapper.vm.$el[elementValue.keyName || key]).toBe(elementValue.new);\n    });\n  });\n\n  it('emits an update event with the input value', () => {\n    const modelValue = 'original value';\n\n    const wrapper = shallowMount(TRadio, {\n      props: {\n        modelValue,\n      },\n    });\n\n    const inputValue = 'new value';\n\n    wrapper.setValue(inputValue);\n\n    expect(wrapper.emitted('update:modelValue')).toBeTruthy();\n\n    // assert event count\n    expect(wrapper.emitted('update:modelValue')?.length).toBe(1);\n\n    // assert event payload\n    expect(wrapper.emitted('update:modelValue')![0]).toEqual([inputValue]);\n  });\n\n  it('emits native input events', () => {\n    const onChange = jest.fn();\n    const onBlur = jest.fn();\n    const onFocus = jest.fn();\n    const onKeyup = jest.fn();\n    const onInput = jest.fn();\n\n    const wrapper = shallowMount(TRadio, {\n      attrs: {\n        onChange,\n        onBlur,\n        onFocus,\n        onKeyup,\n        onInput,\n      },\n    });\n\n    const input = wrapper.vm.$el;\n\n    input.dispatchEvent(new Event('change'));\n    expect(onChange).toHaveBeenCalled();\n\n    input.dispatchEvent(new FocusEvent('focus'));\n    expect(onFocus).toHaveBeenCalled();\n\n    input.dispatchEvent(new FocusEvent('blur'));\n    expect(onBlur).toHaveBeenCalled();\n\n    input.dispatchEvent(new InputEvent('input'));\n    expect(onInput).toHaveBeenCalled();\n\n    input.dispatchEvent(new KeyboardEvent('keyup', { key: 'a' }));\n    expect(onKeyup).toHaveBeenCalled();\n  });\n\n  it('has native input methods', () => {\n    const wrapper = shallowMount(TRadio);\n\n    const input = wrapper.vm.$el;\n\n    expect(typeof input.click).toBe('function');\n    expect(typeof input.focus).toBe('function');\n  });\n\n  it('triggers custom events', async () => {\n    const onCustom = jest.fn();\n\n    const wrapper = shallowMount(TRadio, {\n      attrs: {\n        onCustom,\n      },\n    });\n    const input = wrapper.vm.$el as HTMLInputElement;\n\n    const evt = new CustomEvent('custom', { detail: 'my-custom-event' });\n    input.dispatchEvent(evt);\n\n    expect(onCustom).toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "src/__tests/components/TRichSelect/RichSelectClearButton.spec.ts",
    "content": "import { shallowMount } from '@vue/test-utils';\nimport RichSelectClearButton from '../../../components/TRichSelect/RichSelectClearButton.vue';\n\ndescribe('RichSelectClearButton', () => {\n  it('renders the component', () => {\n    const wrapper = shallowMount(RichSelectClearButton);\n    expect(wrapper.vm.$el.tagName).toBe('BUTTON');\n  });\n});\n"
  },
  {
    "path": "src/__tests/components/TRichSelect/RichSelectDropdown.spec.ts",
    "content": "import { NormalizedOptions } from '@variantjs/core';\nimport { shallowMount } from '@vue/test-utils';\nimport { computed } from 'vue';\nimport RichSelectDropdown from '../../../components/TRichSelect/RichSelectDropdown.vue';\nimport { getChildComponentNameByRef } from '../../testUtils';\n\ndescribe('RichSelectDropdown', () => {\n  const options: NormalizedOptions = [{\n    value: 'a',\n    text: 'a',\n  }];\n\n  const showSearchInput = computed(() => true);\n\n  it('renders the component', () => {\n    const wrapper = shallowMount(RichSelectDropdown, {\n      global: {\n        provide: {\n          options,\n          showSearchInput,\n        },\n      },\n    });\n\n    expect(wrapper.vm.$el.tagName).toBe('DIV');\n  });\n\n  it('has a RichSelectOptionsList component', () => {\n    const wrapper = shallowMount(RichSelectDropdown, {\n      global: {\n        provide: {\n          showSearchInput,\n          options,\n        },\n      },\n    });\n\n    expect(getChildComponentNameByRef(wrapper, 'optionsList')).toEqual('RichSelectOptionsList');\n  });\n\n  it('has a RichSelectSearchInput  component', () => {\n    const wrapper = shallowMount(RichSelectDropdown, {\n      global: {\n        provide: {\n          showSearchInput,\n          options,\n        },\n      },\n    });\n\n    expect(getChildComponentNameByRef(wrapper, 'searchInput')).toEqual('RichSelectSearchInput');\n  });\n\n  it('hides the RichSelectSearchInput component if `showSearchInput` is `false`', () => {\n    const wrapper = shallowMount(RichSelectDropdown, {\n      global: {\n        provide: {\n          options,\n          showSearchInput: computed(() => false),\n        },\n      },\n    });\n\n    expect(getChildComponentNameByRef(wrapper, 'searchInput')).toBeUndefined();\n  });\n});\n"
  },
  {
    "path": "src/__tests/components/TRichSelect/RichSelectOption.spec.ts",
    "content": "/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { NormalizedOption } from '@variantjs/core';\nimport { mount, shallowMount } from '@vue/test-utils';\nimport { ref } from 'vue';\nimport RichSelectOption from '../../../components/TRichSelect/RichSelectOption.vue';\n\ndescribe('RichSelectOption', () => {\n  const scrollIntoViewMock = jest.fn();\n  window.HTMLLIElement.prototype.scrollIntoView = scrollIntoViewMock;\n\n  const toggleOption = jest.fn();\n  const setActiveOption = jest.fn();\n  const optionIsSelected = jest.fn();\n  const optionIsActive = jest.fn();\n  const shown = ref(true);\n  const option: NormalizedOption = {\n    value: 'a',\n    text: 'Option A',\n  };\n  const deep = 0;\n\n  const global = {\n    provide: {\n      toggleOption,\n      setActiveOption,\n      optionIsSelected,\n      optionIsActive,\n      shown,\n    },\n    stubs: {\n      RichSelectOptionsList: {\n        template: '<div />',\n      },\n    },\n  };\n\n  afterEach(() => {\n    jest.clearAllMocks();\n\n    optionIsActive.mockReturnValue(false);\n\n    scrollIntoViewMock.mockReset();\n  });\n\n  it('renders the component', () => {\n    const wrapper = shallowMount(RichSelectOption, {\n      props: {\n        option,\n        deep,\n      },\n      global,\n    });\n\n    expect(wrapper.vm.$el.tagName).toBe('LI');\n    expect(wrapper.vm.$el.textContent).toBe('Option A');\n  });\n\n  it('determines if option has children', () => {\n    const wrapper = shallowMount(RichSelectOption, {\n      props: {\n        option,\n        deep,\n      },\n      global,\n    });\n\n    expect(wrapper.vm.hasChildren).toBe(false);\n  });\n\n  it('determines if option has children when empty', () => {\n    const wrapper = shallowMount(RichSelectOption, {\n      props: {\n        option: {\n          ...option,\n          children: [],\n        },\n        deep,\n      },\n      global,\n    });\n\n    expect(wrapper.vm.hasChildren).toBe(false);\n  });\n\n  it('determines if option has children when not empty', () => {\n    const wrapper = shallowMount(RichSelectOption, {\n      props: {\n        option: {\n          ...option,\n          children: [\n            { value: 1, text: 1 },\n          ],\n        },\n        deep,\n      },\n      global,\n    });\n\n    expect(wrapper.vm.hasChildren).toBe(true);\n  });\n\n  it('determines if option is selected', () => {\n    optionIsSelected.mockReturnValue(true);\n\n    const wrapper = shallowMount(RichSelectOption, {\n      props: {\n        option,\n        deep,\n      },\n      global,\n    });\n\n    expect(wrapper.vm.isSelected).toBe(true);\n  });\n\n  it('determines if option is selected when false', () => {\n    optionIsSelected.mockReturnValue(false);\n\n    const wrapper = shallowMount(RichSelectOption, {\n      props: {\n        option,\n        deep,\n      },\n      global,\n    });\n\n    expect(wrapper.vm.isSelected).toBe(false);\n  });\n\n  it('determines if option is active', () => {\n    optionIsActive.mockReturnValue(true);\n\n    const wrapper = shallowMount(RichSelectOption, {\n      props: {\n        option,\n        deep,\n      },\n      global,\n    });\n\n    jest.spyOn(wrapper.vm, 'scrollIntoViewIfNeccesary').mockImplementation(() => {});\n\n    expect(wrapper.vm.isActive).toBe(true);\n  });\n\n  it('determines if option is active when false', () => {\n    optionIsActive.mockReturnValue(false);\n\n    const wrapper = shallowMount(RichSelectOption, {\n      props: {\n        option,\n        deep,\n      },\n      global,\n    });\n\n    expect(wrapper.vm.isActive).toBe(false);\n  });\n\n  it('shows the checkmark icon if option is selected', () => {\n    optionIsSelected.mockReturnValue(true);\n\n    const wrapper = mount(RichSelectOption, {\n      props: {\n        option,\n        deep,\n      },\n      global,\n    });\n\n    expect(wrapper.vm.$refs.checkIcon).toBeDefined();\n  });\n\n  it('hides the checkmark icon if option is not selected', () => {\n    optionIsSelected.mockReturnValue(false);\n\n    const wrapper = mount(RichSelectOption, {\n      props: {\n        option,\n        deep,\n      },\n      global,\n    });\n\n    expect(wrapper.vm.$refs.checkIcon).toBeUndefined();\n  });\n\n  it('will scroll into the view if shown and is active', async () => {\n    optionIsActive.mockReturnValue(true);\n\n    const wrapper = shallowMount(RichSelectOption, {\n      props: {\n        option,\n        deep,\n      },\n      global,\n    });\n\n    wrapper.vm.$el.scrollIntoView = scrollIntoViewMock;\n\n    await wrapper.vm.$nextTick();\n\n    expect(scrollIntoViewMock).toHaveBeenCalled();\n  });\n\n  it('will scroll into the view if active changes state', async () => {\n    optionIsActive.mockReturnValue(true);\n\n    const wrapper = shallowMount(RichSelectOption, {\n      props: {\n        option,\n        deep,\n      },\n      global,\n    });\n\n    await wrapper.vm.$nextTick();\n    // First time when created\n    expect(scrollIntoViewMock).toHaveBeenCalledTimes(1);\n\n    (wrapper.vm.$options.watch!.isActive as any).call(wrapper.vm);\n\n    // Second time when state changed\n    expect(scrollIntoViewMock).toHaveBeenCalledTimes(2);\n  });\n\n  it('will not scroll into the view if shown but is not active', async () => {\n    optionIsActive.mockReturnValue(false);\n\n    const wrapper = shallowMount(RichSelectOption, {\n      props: {\n        option,\n        deep,\n      },\n      global,\n    });\n\n    wrapper.vm.$el.scrollIntoView = scrollIntoViewMock;\n\n    await wrapper.vm.$nextTick();\n\n    expect(scrollIntoViewMock).not.toHaveBeenCalled();\n  });\n\n  it('will not scroll into the view if is active but is not shown', async () => {\n    optionIsActive.mockReturnValue(true);\n\n    const wrapper = shallowMount(RichSelectOption, {\n      props: {\n        option,\n        deep,\n      },\n      global: {\n        provide: {\n          ...global.provide,\n          shown: ref(false),\n        },\n        stubs: global.stubs,\n      },\n    });\n\n    wrapper.vm.$el.scrollIntoView = scrollIntoViewMock;\n\n    await wrapper.vm.$nextTick();\n\n    expect(scrollIntoViewMock).not.toHaveBeenCalled();\n  });\n\n  describe('event handlers', () => {\n    it('calls the `mousemoveHandler` when option mousemove', () => {\n      const wrapper = shallowMount(RichSelectOption, {\n        props: {\n          option,\n          deep,\n        },\n        global,\n      });\n\n      const mousemoveHandlerSpy = jest.spyOn(wrapper.vm, 'mousemoveHandler');\n\n      wrapper.vm.$el.dispatchEvent(new MouseEvent('mousemove'));\n\n      expect(mousemoveHandlerSpy).toHaveBeenCalled();\n    });\n\n    it('calls setActiveOption method when `mousemoveHandler` called', () => {\n      const wrapper = shallowMount(RichSelectOption, {\n        props: {\n          option,\n          deep,\n        },\n        global,\n      });\n\n      wrapper.vm.mousemoveHandler();\n\n      expect(setActiveOption).toHaveBeenCalledWith(option);\n    });\n\n    it('doesnt call setActiveOption method when `mousemoveHandler` called and option is disabled', () => {\n      const wrapper = shallowMount(RichSelectOption, {\n        props: {\n          option: {\n            ...option,\n            disabled: true,\n          },\n          deep,\n        },\n        global,\n      });\n\n      wrapper.vm.mousemoveHandler();\n\n      expect(setActiveOption).not.toHaveBeenCalled();\n    });\n\n    it('calls the `mousewheelHandler` when mousewheel event', () => {\n      const wrapper = shallowMount(RichSelectOption, {\n        props: {\n          option,\n          deep,\n        },\n        global,\n      });\n\n      const mousewheelHandlerSpy = jest.spyOn(wrapper.vm, 'mousewheelHandler');\n\n      wrapper.vm.$el.dispatchEvent(new MouseEvent('mousewheel'));\n\n      expect(mousewheelHandlerSpy).toHaveBeenCalled();\n    });\n\n    it('call setActiveOption method when `mousewheelHandler` is called ', () => {\n      const wrapper = shallowMount(RichSelectOption, {\n        props: {\n          option,\n          deep,\n        },\n        global,\n      });\n\n      wrapper.vm.mousewheelHandler();\n\n      expect(setActiveOption).toHaveBeenCalledWith(option);\n    });\n\n    it('doesnt call setActiveOption method when `mousewheelHandler` is called and option is disabled', () => {\n      const wrapper = shallowMount(RichSelectOption, {\n        props: {\n          option: {\n            ...option,\n            disabled: true,\n          },\n          deep,\n        },\n        global,\n      });\n\n      wrapper.vm.mousewheelHandler();\n\n      expect(setActiveOption).not.toHaveBeenCalled();\n    });\n\n    it('calls the `clickHandler` when option clicked', () => {\n      const wrapper = shallowMount(RichSelectOption, {\n        props: {\n          option,\n          deep,\n        },\n        global,\n      });\n\n      const clickHandlerSpy = jest.spyOn(wrapper.vm, 'clickHandler');\n\n      wrapper.vm.$el.dispatchEvent(new MouseEvent('click'));\n\n      expect(clickHandlerSpy).toHaveBeenCalled();\n    });\n\n    it('the `clickHandler` toggles the option', () => {\n      const wrapper = shallowMount(RichSelectOption, {\n        props: {\n          option,\n          deep,\n        },\n        global,\n      });\n\n      wrapper.vm.clickHandler();\n\n      expect(toggleOption).toHaveBeenCalledWith(option);\n    });\n\n    it('doesnt call option toggle method when `clickHandler` is called and option is disabled', () => {\n      const wrapper = shallowMount(RichSelectOption, {\n        props: {\n          option: {\n            ...option,\n            disabled: true,\n          },\n          deep,\n        },\n        global,\n      });\n\n      wrapper.vm.clickHandler();\n\n      expect(toggleOption).not.toHaveBeenCalled();\n    });\n  });\n\n  describe('regular option attributes', () => {\n    it('has the correct `aria-selected` attribute when is selected', () => {\n      optionIsSelected.mockReturnValue(true);\n\n      const wrapper = shallowMount(RichSelectOption, {\n        props: {\n          option,\n          deep,\n        },\n        global,\n      });\n\n      expect(wrapper.vm.$el.querySelector('button').getAttribute('aria-selected')).toBe('true');\n    });\n\n    it('has the correct `aria-selected` attribute when is not selected', () => {\n      optionIsSelected.mockReturnValue(false);\n\n      const wrapper = shallowMount(RichSelectOption, {\n        props: {\n          option,\n          deep,\n        },\n        global,\n      });\n\n      expect(wrapper.vm.$el.querySelector('button').getAttribute('aria-selected')).toBe('false');\n    });\n\n    it('has the role=option attribute', () => {\n      const wrapper = shallowMount(RichSelectOption, {\n        props: {\n          option,\n          deep,\n        },\n        global,\n      });\n\n      expect(wrapper.vm.$el.querySelector('button').getAttribute('role')).toBe('option');\n    });\n    it('has the tabindex=-1 attribute', () => {\n      const wrapper = shallowMount(RichSelectOption, {\n        props: {\n          option,\n          deep,\n        },\n        global,\n      });\n\n      expect(wrapper.vm.$el.querySelector('button').getAttribute('tabindex')).toBe('-1');\n    });\n\n    it.each([1, 'foo', undefined, NaN])('adds a value attribute for regular values with %s', (value) => {\n      const wrapper = shallowMount(RichSelectOption, {\n        props: {\n          option: {\n            value,\n            text: 'Foo',\n          },\n          deep,\n        },\n        global,\n      });\n\n      expect(wrapper.vm.$el.querySelector('button').getAttribute('value')).toBe(String(value));\n    });\n\n    it.each([{ foo: 'bar' }, [1, 2], null])('adds a value attribute for objects %s', (value) => {\n      const wrapper = shallowMount(RichSelectOption, {\n        props: {\n          option: {\n            value,\n            text: 'Foo',\n          },\n          deep,\n        } as any,\n        global,\n      });\n\n      expect(wrapper.vm.$el.querySelector('button').getAttribute('value')).toBe(JSON.stringify(value));\n    });\n  });\n\n  describe('option classes', () => {\n    const classesList = {\n      option: 'option',\n      selectedHighlightedOption: 'selected-highlighted-option',\n      selectedOption: 'selected-option',\n      highlightedOption: 'highlighted-option',\n    };\n\n    const configuration = { classesList };\n\n    it('adds the selectedHighlightedOption if option is selected an active', () => {\n      optionIsSelected.mockReturnValue(true);\n      optionIsActive.mockReturnValue(true);\n\n      const wrapper = shallowMount(RichSelectOption, {\n        props: {\n          option,\n          deep,\n        },\n        global: {\n          ...global,\n          provide: {\n            ...global.provide,\n            configuration,\n          },\n        },\n      });\n\n      expect(wrapper.vm.$el.querySelector('button').getAttribute('class')).toBe('option selected-highlighted-option');\n    });\n\n    it('adds the selectedOption if option is selected but is not active', () => {\n      optionIsSelected.mockReturnValue(true);\n      optionIsActive.mockReturnValue(false);\n\n      const wrapper = shallowMount(RichSelectOption, {\n        props: {\n          option,\n          deep,\n        },\n        global: {\n          ...global,\n          provide: {\n            ...global.provide,\n            configuration,\n          },\n        },\n      });\n\n      expect(wrapper.vm.$el.querySelector('button').getAttribute('class')).toBe('option selected-option');\n    });\n\n    it('adds the highlightedOption if option is active but is not selected', () => {\n      optionIsSelected.mockReturnValue(false);\n      optionIsActive.mockReturnValue(true);\n\n      const wrapper = shallowMount(RichSelectOption, {\n        props: {\n          option,\n          deep,\n        },\n        global: {\n          ...global,\n          provide: {\n            ...global.provide,\n            configuration,\n          },\n        },\n      });\n\n      expect(wrapper.vm.$el.querySelector('button').getAttribute('class')).toBe('option highlighted-option');\n    });\n  });\n\n  describe('option has children', () => {\n    const wrapper = shallowMount(RichSelectOption, {\n      props: {\n        option: {\n          value: 'foo',\n          text: 'Foo',\n          children: [{ value: 1, text: 1 }],\n        },\n        deep: 0,\n      },\n      global,\n    });\n\n    it('has the role=optgroup attribute', () => {\n      expect(wrapper.vm.$el.getAttribute('role')).toBe('optgroup');\n    });\n\n    it('has the option  text', () => {\n      expect(wrapper.vm.$el.textContent).toBe('Foo');\n    });\n\n    it('shows the childrenOptions component', () => {\n      expect(wrapper.vm.$refs.childrenOptions).toBeDefined();\n    });\n  });\n});\n"
  },
  {
    "path": "src/__tests/components/TRichSelect/RichSelectOptionsList.spec.ts",
    "content": "/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { NormalizedOptions } from '@variantjs/core';\nimport { shallowMount } from '@vue/test-utils';\nimport { ref } from 'vue';\nimport RichSelectOptionsList from '../../../components/TRichSelect/RichSelectOptionsList.vue';\nimport { TSelectOptions } from '../../../types';\n\ndescribe('RichSelectOptionsList', () => {\n  const options: NormalizedOptions = [\n    {\n      value: 'A',\n      text: 'Option A',\n    },\n    {\n      value: 'B',\n      text: 'Option B',\n    },\n  ];\n\n  const props = {\n    options,\n    deep: 0,\n  };\n\n  const global = {\n    provide: {\n      configuration: {} as TSelectOptions,\n      fetchingMoreOptions: ref(false),\n      shown: ref(false),\n      dropdownBottomReachedHandler: jest.fn(),\n    },\n  };\n\n  it('should render without errors', () => {\n    const wrapper = shallowMount(RichSelectOptionsList, { props, global });\n    expect(wrapper.vm.$el.tagName).toBe('UL');\n  });\n\n  it('doesnt have `style` attribute by default', () => {\n    const wrapper = shallowMount(RichSelectOptionsList, { props, global });\n    expect(wrapper.vm.$el.getAttribute('style')).toBeNull();\n  });\n\n  it('adds the max-height style if defined on the settings', () => {\n    const configuration: TSelectOptions = {\n      maxHeight: 100,\n    };\n    const wrapper = shallowMount(RichSelectOptionsList, {\n      props,\n      global: {\n        provide: {\n          ...global.provide,\n          configuration,\n        },\n      },\n    });\n\n    expect(wrapper.vm.$el.getAttribute('style')).toBe('max-height: 100px; overflow-x: auto;');\n  });\n\n  it('doesnt add the max-height style if deep > 0', () => {\n    const configuration: TSelectOptions = {\n      maxHeight: 100,\n    };\n    const wrapper = shallowMount(RichSelectOptionsList, {\n      props: {\n        options,\n        deep: 1,\n      },\n      global: {\n        provide: {\n          ...global.provide,\n          configuration,\n        },\n      },\n    });\n\n    expect(wrapper.vm.$el.getAttribute('style')).toBeNull();\n  });\n\n  it('adds every option', () => {\n    const wrapper = shallowMount(RichSelectOptionsList, {\n      props,\n      global,\n    });\n\n    expect(wrapper.findAll('rich-select-option-stub').length).toBe(options.length);\n  });\n\n  it('scroll the list to the \"fetchingMoreOptions\" element after loaded more options ends', async () => {\n    const fetchingMoreOptions = ref(false);\n\n    const scrollElementMock = jest.fn();\n    window.HTMLLIElement.prototype.scrollIntoView = scrollElementMock;\n\n    const wrapper = shallowMount(RichSelectOptionsList, {\n      props,\n      global: {\n        provide: {\n          ...global.provide,\n          fetchingMoreOptions,\n        },\n      },\n    });\n\n    expect(scrollElementMock).not.toHaveBeenCalled();\n\n    fetchingMoreOptions.value = true;\n\n    await wrapper.vm.$nextTick();\n    await wrapper.vm.$nextTick();\n\n    expect(scrollElementMock).toHaveBeenCalledTimes(1);\n\n    // Should not call again when `fetchingMoreOptions` is false again\n    fetchingMoreOptions.value = false;\n\n    await wrapper.vm.$nextTick();\n    await wrapper.vm.$nextTick();\n\n    expect(scrollElementMock).toHaveBeenCalledTimes(1);\n  });\n\n  describe('dropdownBottomReachedHandler', () => {\n    it('adds a scroll listener attached to the bottomReachedObserver when component is mounted', () => {\n      const addEventListenerSpy = jest.spyOn(window.HTMLUListElement.prototype, 'addEventListener');\n\n      const wrapper = shallowMount(RichSelectOptionsList, {\n        props,\n        global,\n      });\n\n      expect(addEventListenerSpy).toHaveBeenCalledWith('scroll', (wrapper.vm.$ as any).setupState.bottomReachedObserver);\n\n      addEventListenerSpy.mockRestore();\n    });\n\n    it('doesnt adds a scroll listener if no options list', () => {\n      const addEventListenerSpy = jest.spyOn(window.HTMLUListElement.prototype, 'addEventListener');\n\n      shallowMount(RichSelectOptionsList, {\n        props: {\n          ...props,\n          options: [],\n        },\n        global,\n      });\n\n      expect(addEventListenerSpy).not.toHaveBeenCalled();\n\n      addEventListenerSpy.mockRestore();\n    });\n\n    it('adds a scroll listener once it have options list and is rendered', async () => {\n      const addEventListenerSpy = jest.spyOn(window.HTMLUListElement.prototype, 'addEventListener');\n\n      const wrapper = shallowMount(RichSelectOptionsList, {\n        props: {\n          ...props,\n          options: [],\n        },\n        global,\n      });\n\n      expect(addEventListenerSpy).not.toHaveBeenCalled();\n\n      await wrapper.setProps({\n        options: [{ value: 'a', text: 'A' }],\n      });\n\n      // Not called yet since the element is not in the DOM yet\n      expect(addEventListenerSpy).not.toHaveBeenCalled();\n\n      await wrapper.vm.$nextTick();\n\n      expect(addEventListenerSpy).toHaveBeenCalledWith('scroll', (wrapper.vm.$ as any).setupState.bottomReachedObserver);\n\n      addEventListenerSpy.mockRestore();\n    });\n\n    it('removes the scroll listener when no longer have options list', async () => {\n      const removeEventListenerSpy = jest.spyOn(window.HTMLUListElement.prototype, 'removeEventListener');\n\n      const wrapper = shallowMount(RichSelectOptionsList, {\n        props,\n        global,\n      });\n\n      await wrapper.setProps({\n        options: [],\n      });\n\n      expect(removeEventListenerSpy).toHaveBeenCalledWith('scroll', (wrapper.vm.$ as any).setupState.bottomReachedObserver);\n\n      removeEventListenerSpy.mockRestore();\n    });\n\n    it('removes the scroll listener when component is unmounted', () => {\n      const removeEventListenerSpy = jest.spyOn(window.HTMLUListElement.prototype, 'removeEventListener');\n\n      const wrapper = shallowMount(RichSelectOptionsList, {\n        props,\n        global,\n      });\n\n      wrapper.unmount();\n\n      expect(removeEventListenerSpy).toHaveBeenCalledWith('scroll', (wrapper.vm.$ as any).setupState.bottomReachedObserver);\n\n      removeEventListenerSpy.mockRestore();\n    });\n\n    it('doesnt removes the scroll listener when component is unmounted if no options', () => {\n      const removeEventListenerSpy = jest.spyOn(window.HTMLUListElement.prototype, 'removeEventListener');\n\n      const wrapper = shallowMount(RichSelectOptionsList, {\n        props: {\n          ...props,\n          options: [],\n        },\n        global,\n      });\n\n      wrapper.unmount();\n\n      expect(removeEventListenerSpy).not.toHaveBeenCalled();\n\n      removeEventListenerSpy.mockRestore();\n    });\n\n    it('calls the dropdownBottomReachedHandler when bottom reached', () => {\n      const dropdownBottomReachedHandlerMock = jest.fn();\n\n      jest.useFakeTimers();\n\n      const wrapper = shallowMount(RichSelectOptionsList, {\n        props,\n        global: {\n          provide: {\n            ...global.provide,\n            dropdownBottomReachedHandler: dropdownBottomReachedHandlerMock,\n          },\n        },\n      });\n\n      const container = wrapper.vm.$el;\n\n      jest.spyOn(container, 'clientHeight', 'get').mockReturnValue(100);\n      // 150 - 49 != 100 (which is the not height of the container) meaning it\n      // not reached the bottom yet\n      jest.spyOn(container, 'scrollHeight', 'get').mockReturnValue(150);\n      jest.spyOn(container, 'scrollTop', 'get').mockReturnValue(49);\n\n      container.dispatchEvent(new Event('scroll', {\n        target: container,\n      } as any));\n\n      // (is debounced 200ms)\n      jest.advanceTimersByTime(200);\n      expect(dropdownBottomReachedHandlerMock).not.toHaveBeenCalled();\n\n      // 150 - 50 === 100 (meaning reached the bottom)\n      jest.spyOn(container, 'scrollTop', 'get').mockReturnValue(50);\n\n      container.dispatchEvent(new Event('scroll', {\n        target: container,\n      } as any));\n\n      // (is debounced 200ms)\n      jest.advanceTimersByTime(199);\n      expect(dropdownBottomReachedHandlerMock).not.toHaveBeenCalled();\n      jest.advanceTimersByTime(1);\n      expect(dropdownBottomReachedHandlerMock).toHaveBeenCalled();\n\n      jest.useRealTimers();\n    });\n  });\n});\n"
  },
  {
    "path": "src/__tests/components/TRichSelect/RichSelectSearchInput.spec.ts",
    "content": "/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { shallowMount } from '@vue/test-utils';\nimport { ref } from 'vue';\nimport RichSelectSearchInput from '../../../components/TRichSelect/RichSelectSearchInput.vue';\n\ndescribe('RichSelectSearchInput', () => {\n  const keydownDownHandler = jest.fn();\n  const keydownUpHandler = jest.fn();\n  const keydownEnterHandler = jest.fn();\n  const keydownEscHandler = jest.fn();\n\n  const global = {\n    provide: {\n      shown: ref(true),\n      searchQuery: ref(''),\n      keydownDownHandler,\n      keydownUpHandler,\n      keydownEnterHandler,\n      keydownEscHandler,\n    },\n  };\n\n  let wrapper: any;\n  let search: HTMLInputElement;\n\n  beforeEach(() => {\n    wrapper = shallowMount(RichSelectSearchInput, { global });\n\n    search = wrapper.vm.$refs.search as HTMLInputElement;\n  });\n\n  it('renders the component without errors', () => {\n    expect(wrapper.vm.$el.tagName).toBe('DIV');\n  });\n\n  it('calls the keydownDownHandler when down key pressed', () => {\n    const event = new KeyboardEvent('keydown', { key: 'ArrowDown' });\n\n    search.dispatchEvent(event);\n\n    expect(keydownDownHandler).toHaveBeenCalled();\n  });\n\n  it('calls the keydownUpHandler when down key pressed', () => {\n    const event = new KeyboardEvent('keydown', { key: 'ArrowUp' });\n\n    search.dispatchEvent(event);\n\n    expect(keydownUpHandler).toHaveBeenCalled();\n  });\n\n  it('calls the keydownEnterHandler when down key pressed', () => {\n    const event = new KeyboardEvent('keydown', { key: 'enter' });\n\n    search.dispatchEvent(event);\n\n    expect(keydownEnterHandler).toHaveBeenCalled();\n  });\n\n  it('calls the keydownEscHandler when down key pressed', () => {\n    const event = new KeyboardEvent('keydown', { key: 'esc' });\n\n    search.dispatchEvent(event);\n\n    expect(keydownEscHandler).toHaveBeenCalled();\n  });\n\n  it('focus the search field after is shown', async () => {\n    const shown = ref(false);\n\n    wrapper = shallowMount(RichSelectSearchInput, {\n      global: {\n        provide: {\n          ...global.provide,\n          shown,\n        },\n      },\n    });\n\n    const searchInput = wrapper.vm.$el.querySelector('input');\n\n    const focusSpy = jest.spyOn(searchInput, 'focus');\n\n    shown.value = true;\n\n    await wrapper.vm.$nextTick();\n\n    await wrapper.vm.$nextTick();\n\n    expect(focusSpy).toHaveBeenCalled();\n\n    focusSpy.mockRestore();\n  });\n\n  it('doesnt focus the search field after is hidden', async () => {\n    const shown = ref(true);\n\n    wrapper = shallowMount(RichSelectSearchInput, {\n      global: {\n        provide: {\n          ...global.provide,\n          shown,\n        },\n      },\n    });\n\n    const searchInput = wrapper.vm.$el.querySelector('input');\n\n    const focusSpy = jest.spyOn(searchInput, 'focus');\n\n    shown.value = false;\n\n    await wrapper.vm.$nextTick();\n\n    await wrapper.vm.$nextTick();\n\n    expect(focusSpy).not.toHaveBeenCalled();\n\n    focusSpy.mockRestore();\n  });\n});\n"
  },
  {
    "path": "src/__tests/components/TRichSelect/RichSelectState.spec.ts",
    "content": "import { NormalizedOption } from '@variantjs/core';\nimport { shallowMount } from '@vue/test-utils';\nimport { computed, ref } from 'vue';\nimport RichSelectState from '../../../components/TRichSelect/RichSelectState.vue';\n\ndescribe('RichSelectState', () => {\n  const configuration = {\n    noResultsText: 'No results',\n    searchingText: 'Searching...',\n  };\n  const options = computed<NormalizedOption[]>(() => ([{ value: 'a', text: 'A' }]));\n  const fetchingOptions = ref<boolean>(false);\n  const needsMoreCharsToFetch = ref<boolean>(false);\n  const needsMoreCharsMessage = ref<string>('Needs more chars');\n\n  const global = {\n    provide: {\n      configuration,\n      options,\n      fetchingOptions,\n      needsMoreCharsToFetch,\n      needsMoreCharsMessage,\n    },\n  };\n\n  beforeEach(() => {\n    fetchingOptions.value = false;\n    needsMoreCharsToFetch.value = false;\n  });\n\n  describe('have options', () => {\n    const wrapper = shallowMount(RichSelectState, { global });\n\n    it('doesnt render anything by default', () => {\n      expect(wrapper.text()).toBe('');\n    });\n\n    it('renders the searching text if fetchingOptions', async () => {\n      fetchingOptions.value = true;\n\n      await wrapper.vm.$nextTick();\n\n      expect(wrapper.text()).toBe('Searching...');\n    });\n\n    it('renders the searching text if fetchingOptions and need more chars', async () => {\n      fetchingOptions.value = true;\n      needsMoreCharsToFetch.value = true;\n\n      await wrapper.vm.$nextTick();\n\n      expect(wrapper.text()).toBe('Searching...');\n    });\n\n    it('renders the need more chars message if need more chars', async () => {\n      needsMoreCharsToFetch.value = true;\n\n      await wrapper.vm.$nextTick();\n\n      expect(wrapper.text()).toBe('Needs more chars');\n    });\n  });\n\n  describe('doesnt have options', () => {\n    const wrapper = shallowMount(RichSelectState, {\n      global: {\n        provide: {\n          ...global.provide,\n          options: computed(() => []),\n        },\n      },\n    });\n\n    it('shows the noResultsText by default', async () => {\n      expect(wrapper.text()).toBe('No results');\n    });\n\n    it('doesnt shows the noResultsText if it need more chars to fetch ', async () => {\n      needsMoreCharsToFetch.value = true;\n\n      await wrapper.vm.$nextTick();\n\n      expect(wrapper.text()).toBe('Needs more chars');\n    });\n\n    it('renders the searching text if fetchingOptions and need more chars', async () => {\n      fetchingOptions.value = true;\n      needsMoreCharsToFetch.value = true;\n\n      await wrapper.vm.$nextTick();\n\n      expect(wrapper.text()).toBe('Searching...');\n    });\n  });\n});\n"
  },
  {
    "path": "src/__tests/components/TRichSelect/RichSelectTrigger.spec.ts",
    "content": "import { NormalizedOption } from '@variantjs/core';\nimport { shallowMount } from '@vue/test-utils';\nimport { computed, ref } from 'vue';\nimport RichSelectTrigger from '../../../components/TRichSelect/RichSelectTrigger.vue';\n\ndescribe('RichSelectTrigger', () => {\n  const selectedOption = computed<NormalizedOption | undefined>(() => undefined);\n  const configuration = {};\n  const hasSelectedOption = ref(false);\n\n  const global = {\n    provide: {\n      shown: ref(false),\n      usesTags: ref(false),\n      fetchingOptions: ref(false),\n      selectedOption,\n      hasSelectedOption,\n      configuration,\n    },\n  };\n\n  it('will show the placeholder if not option selected', () => {\n    const wrapper = shallowMount(RichSelectTrigger, { global });\n\n    expect(wrapper.find('text-placeholder-stub').exists()).toBe(true);\n    expect(wrapper.find('span').exists()).toBe(false);\n  });\n\n  it('will show option selected text', () => {\n    const wrapper = shallowMount(RichSelectTrigger, {\n      global: {\n        provide: {\n          ...global.provide,\n          selectedOption: computed<NormalizedOption | undefined>(() => ({\n            value: 'foo',\n            text: 'Foo Bar',\n          })),\n          hasSelectedOption: ref(true),\n          configuration,\n        },\n      },\n    });\n\n    expect(wrapper.find('text-placeholder-stub').exists()).toBe(false);\n    expect(wrapper.find('span').text()).toBe('Foo Bar');\n  });\n\n  it('will show the selector icon if is not clearable', () => {\n    const wrapper = shallowMount(RichSelectTrigger, {\n      global: {\n        provide: {\n          ...global.provide,\n          configuration: {\n            clearable: false,\n          },\n        },\n      },\n    });\n\n    expect(wrapper.vm.showSelectorIcon).toBe(true);\n    expect(wrapper.find('selector-icon-stub').exists()).toBe(true);\n  });\n\n  it('will show the selector icon if is disabled', () => {\n    const wrapper = shallowMount(RichSelectTrigger, {\n      global: {\n        provide: {\n          ...global.provide,\n          configuration: {\n            disabled: true,\n          },\n        },\n      },\n    });\n\n    expect(wrapper.vm.showSelectorIcon).toBe(true);\n    expect(wrapper.find('selector-icon-stub').exists()).toBe(true);\n  });\n\n  it('will show the selector icon if is disabled and have a selected option', () => {\n    const wrapper = shallowMount(RichSelectTrigger, {\n      global: {\n        provide: {\n          ...global.provide,\n          configuration: {\n            disabled: true,\n          },\n          selectedOption: computed<NormalizedOption | undefined>(() => ({\n            value: 'foo',\n            text: 'Foo Bar',\n          })),\n          hasSelectedOption: ref(true),\n        },\n      },\n    });\n\n    expect(wrapper.vm.showSelectorIcon).toBe(true);\n    expect(wrapper.find('selector-icon-stub').exists()).toBe(true);\n  });\n\n  it('will  show the selector icon if clearable and doesnt have selected option', () => {\n    const wrapper = shallowMount(RichSelectTrigger, {\n      global: {\n        provide: {\n          ...global.provide,\n          configuration: {\n            clearable: true,\n          },\n        },\n      },\n    });\n\n    expect(wrapper.vm.showSelectorIcon).toBe(true);\n    expect(wrapper.find('selector-icon-stub').exists()).toBe(true);\n  });\n\n  it('will not show the selector icon if clearable and have selected option', () => {\n    const wrapper = shallowMount(RichSelectTrigger, {\n      global: {\n        provide: {\n          ...global.provide,\n          selectedOption: computed<NormalizedOption | undefined>(() => ({\n            value: 'foo',\n            text: 'foo',\n          })),\n          hasSelectedOption: ref(true),\n          configuration: {\n            clearable: true,\n          },\n        },\n      },\n    });\n\n    expect(wrapper.vm.showSelectorIcon).toBe(false);\n    expect(wrapper.find('selector-icon-stub').exists()).toBe(false);\n  });\n\n  describe('label', () => {\n    it('will use the selectedoption text for single values', () => {\n      const wrapper = shallowMount(RichSelectTrigger, {\n        global: {\n          provide: {\n            ...global.provide,\n            selectedOption: computed<NormalizedOption | undefined>(() => ({\n              value: 'foo',\n              text: 'foo bar',\n            })),\n            hasSelectedOption: ref(true),\n          },\n        },\n      });\n\n      expect(wrapper.vm.label).toBe('foo bar');\n    });\n\n    it('will join all the the selectedoption text with a comma for multiple values', () => {\n      const wrapper = shallowMount(RichSelectTrigger, {\n        global: {\n          provide: {\n            ...global.provide,\n            selectedOption: computed<NormalizedOption[]>(() => ([\n              {\n                value: 'foo',\n                text: 'foo bar',\n              },\n              {\n                value: 'bar',\n                text: 'option 2',\n              },\n            ])),\n            hasSelectedOption: ref(true),\n          },\n        },\n      });\n\n      expect(wrapper.vm.label).toBe('foo bar, option 2');\n    });\n\n    it('will return undefined if empty selected option', () => {\n      const wrapper = shallowMount(RichSelectTrigger, {\n        global: {\n          provide: {\n            ...global.provide,\n            selectedOption: computed<undefined>(() => undefined),\n            hasSelectedOption: ref(false),\n          },\n        },\n      });\n\n      expect(wrapper.vm.label).toBeUndefined();\n    });\n  });\n\n  describe('isFetchingOptionsWhileClosed handle', () => {\n    it('considers that isFetchingOptionsWhileClosed if is fetchingOptions is true and is not shown', () => {\n      const wrapper = shallowMount(RichSelectTrigger, {\n        global: {\n          provide: {\n            ...global.provide,\n            fetchingOptions: ref(true),\n            shown: ref(false),\n          },\n        },\n      });\n\n      expect(wrapper.vm.isFetchingOptionsWhileClosed).toBe(true);\n    });\n\n    it('doesnt considers that isFetchingOptionsWhileClosed if is not fetchingOptions', () => {\n      const wrapper = shallowMount(RichSelectTrigger, {\n        global: {\n          provide: {\n            ...global.provide,\n            fetchingOptions: ref(false),\n            shown: ref(false),\n          },\n        },\n      });\n\n      expect(wrapper.vm.isFetchingOptionsWhileClosed).toBe(false);\n    });\n\n    it('doesnt considers that isFetchingOptionsWhileClosed if is fetchingOptions is true but is shown', () => {\n      const wrapper = shallowMount(RichSelectTrigger, {\n        global: {\n          provide: {\n            ...global.provide,\n            fetchingOptions: ref(true),\n            shown: ref(true),\n          },\n        },\n      });\n\n      expect(wrapper.vm.isFetchingOptionsWhileClosed).toBe(false);\n    });\n\n    it('will show a loading... placeholder and loading icon when fetching options while closed', () => {\n      const wrapper = shallowMount(RichSelectTrigger, {\n        global: {\n          provide: {\n            ...global.provide,\n            configuration: {\n              loadingClosedPlaceholder: 'Loading...',\n            },\n            fetchingOptions: ref(true),\n          },\n        },\n      });\n\n      expect(wrapper.vm.$refs.label).not.toBeDefined();\n      expect(wrapper.vm.$refs.placeholder).not.toBeDefined();\n      expect(wrapper.vm.$refs.fetchingPlaceholder).toBeDefined();\n      expect(wrapper.vm.$refs.loadingIcon).toBeDefined();\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      expect((wrapper.vm.$refs.fetchingPlaceholder as any).placeholder).toBe('Loading...');\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      expect((wrapper.vm.$refs.fetchingPlaceholder as any).classProperty).toBe('selectButtonSearchingPlaceholder');\n    });\n  });\n});\n"
  },
  {
    "path": "src/__tests/components/TRichSelect/RichSelectTriggerTags.spec.ts",
    "content": "import { NormalizedOption } from '@variantjs/core';\nimport { shallowMount } from '@vue/test-utils';\nimport { computed } from 'vue';\nimport RichSelectTriggerTags from '../../../components/TRichSelect/RichSelectTriggerTags.vue';\n\ndescribe('RichSelectTriggerTags', () => {\n  it('it renders every option', () => {\n    const selectedOptions = computed<NormalizedOption[]>(() => [\n      { value: 'a', text: 'Value A' },\n      { value: 'b', text: 'Value B' },\n      { value: 'c', text: 'Value C' },\n    ]);\n\n    const wrapper = shallowMount(RichSelectTriggerTags, {\n      global: {\n        provide: {\n          selectedOption: selectedOptions,\n        },\n      },\n    });\n\n    expect(wrapper.findAll('rich-select-trigger-tags-tag-stub')).toHaveLength(3);\n    expect(Object.keys(wrapper.find('rich-select-trigger-tags-tag-stub').attributes())).toEqual(['option']);\n  });\n});\n"
  },
  {
    "path": "src/__tests/components/TRichSelect/RichSelectTriggerTagsTag.spec.ts",
    "content": "import { shallowMount } from '@vue/test-utils';\nimport RichSelectTriggerTagsTag from '../../../components/TRichSelect/RichSelectTriggerTagsTag.vue';\n\ndescribe('RichSelectTriggerTagsTag', () => {\n  const toggleOptionMock = jest.fn();\n  const props = {\n    option: {\n      value: 'a',\n      text: 'Letter A',\n    },\n  };\n\n  const global = {\n    provide: {\n      toggleOption: toggleOptionMock,\n    },\n  };\n\n  afterEach(() => {\n    toggleOptionMock.mockReset();\n\n    jest.clearAllMocks();\n  });\n\n  it('contains the option text', () => {\n    const wrapper = shallowMount(RichSelectTriggerTagsTag, {\n      props,\n      global,\n    });\n\n    expect(wrapper.text()).toEqual('Letter A');\n  });\n\n  describe('event handlers', () => {\n    it('has the focus method attached to the mousedown handler', () => {\n      const wrapper = shallowMount(RichSelectTriggerTagsTag, {\n        global,\n        props,\n      });\n\n      const focusSpy = jest.spyOn(wrapper.vm, 'focus');\n      wrapper.vm.$el.dispatchEvent(new Event('mousedown'));\n      expect(focusSpy).toHaveBeenCalled();\n    });\n\n    it('calls the unselect method when backspace key is pressed', () => {\n      const wrapper = shallowMount(RichSelectTriggerTagsTag, {\n        global,\n        props,\n      });\n\n      const unselectSpy = jest.spyOn(wrapper.vm, 'unselect');\n      wrapper.vm.$el.dispatchEvent(new KeyboardEvent('keydown', { key: 'Backspace' }));\n      expect(unselectSpy).toHaveBeenCalled();\n    });\n\n    it('calls the focusNextElement method when right key is pressed', () => {\n      const wrapper = shallowMount(RichSelectTriggerTagsTag, {\n        global,\n        props,\n      });\n\n      const focusNextElementSpy = jest.spyOn(wrapper.vm, 'focusNextElement');\n      wrapper.vm.$el.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight' }));\n      expect(focusNextElementSpy).toHaveBeenCalled();\n    });\n\n    it('calls the focusPrevElement method when left key is pressed', () => {\n      const wrapper = shallowMount(RichSelectTriggerTagsTag, {\n        global,\n        props,\n      });\n\n      const focusPrevElementSpy = jest.spyOn(wrapper.vm, 'focusPrevElement');\n      wrapper.vm.$el.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowLeft' }));\n      expect(focusPrevElementSpy).toHaveBeenCalled();\n    });\n\n    it('prevents event propagation when enter key is pressed', () => {\n      const wrapper = shallowMount(RichSelectTriggerTagsTag, {\n        global,\n        props,\n      });\n\n      const event = new KeyboardEvent('keydown', { key: 'enter' });\n      const stopPropagationSpy = jest.spyOn(event, 'stopPropagation');\n      wrapper.vm.$el.dispatchEvent(event);\n      expect(stopPropagationSpy).toHaveBeenCalled();\n    });\n  });\n\n  describe('delete button event handlers', () => {\n    it('calls the unselect method when mousedown', () => {\n      const wrapper = shallowMount(RichSelectTriggerTagsTag, {\n        global,\n        props,\n      });\n\n      const deleteButton = wrapper.vm.$el.querySelector('[tabindex=\"0\"]');\n      const unselectSpy = jest.spyOn(wrapper.vm, 'unselect');\n      deleteButton.dispatchEvent(new Event('mousedown'));\n      expect(unselectSpy).toHaveBeenCalled();\n    });\n\n    it('calls the unselect method when backspace pressed', () => {\n      const wrapper = shallowMount(RichSelectTriggerTagsTag, {\n        global,\n        props,\n      });\n\n      const deleteButton = wrapper.vm.$el.querySelector('[tabindex=\"0\"]');\n      const unselectSpy = jest.spyOn(wrapper.vm, 'unselect');\n      deleteButton.dispatchEvent(new KeyboardEvent('keydown', { key: 'Backspace' }));\n      expect(unselectSpy).toHaveBeenCalled();\n    });\n\n    it('calls the unselect method when enter pressed', () => {\n      const wrapper = shallowMount(RichSelectTriggerTagsTag, {\n        global,\n        props,\n      });\n\n      const deleteButton = wrapper.vm.$el.querySelector('[tabindex=\"0\"]');\n      const unselectSpy = jest.spyOn(wrapper.vm, 'unselect');\n      deleteButton.dispatchEvent(new KeyboardEvent('keydown', { key: 'enter' }));\n      expect(unselectSpy).toHaveBeenCalled();\n    });\n  });\n\n  describe('focusNextElement', () => {\n    it('focus the next element', () => {\n      const wrapper = shallowMount(RichSelectTriggerTagsTag, {\n        global,\n        props,\n      });\n\n      const parentElement = document.createElement('div');\n      const nextElement = document.createElement('button');\n\n      [\n        document.createElement('button'),\n        document.createElement('button'),\n        wrapper.vm.$el,\n        nextElement,\n      ].forEach((el) => parentElement.appendChild(el));\n\n      jest.spyOn(window.HTMLButtonElement.prototype, 'parentElement', 'get').mockReturnValue(parentElement);\n\n      const focusSpy = jest.spyOn(nextElement, 'focus');\n\n      wrapper.vm.focusNextElement();\n\n      expect(focusSpy).toHaveBeenCalled();\n    });\n\n    it('doesnt focus the next element if is last index', () => {\n      const wrapper = shallowMount(RichSelectTriggerTagsTag, {\n        global,\n        props,\n      });\n\n      const parentElement = document.createElement('div');\n\n      [\n        document.createElement('button'),\n        document.createElement('button'),\n        wrapper.vm.$el,\n      ].forEach((el) => parentElement.appendChild(el));\n\n      jest.spyOn(window.HTMLButtonElement.prototype, 'parentElement', 'get').mockReturnValue(parentElement);\n\n      const focusSpy = jest.spyOn(window.HTMLButtonElement.prototype, 'focus');\n\n      wrapper.vm.focusNextElement();\n\n      expect(focusSpy).not.toHaveBeenCalled();\n    });\n  });\n\n  describe('focus previous element', () => {\n    it('focus previous element', () => {\n      const wrapper = shallowMount(RichSelectTriggerTagsTag, {\n        global,\n        props,\n      });\n\n      const parentElement = document.createElement('div');\n      const prevElement = document.createElement('button');\n\n      [\n        document.createElement('button'),\n        document.createElement('button'),\n        prevElement,\n        wrapper.vm.$el,\n      ].forEach((el) => parentElement.appendChild(el));\n\n      jest.spyOn(window.HTMLButtonElement.prototype, 'parentElement', 'get').mockReturnValue(parentElement);\n\n      const focusSpy = jest.spyOn(prevElement, 'focus');\n\n      wrapper.vm.focusPrevElement();\n\n      expect(focusSpy).toHaveBeenCalled();\n    });\n\n    it('doesnt focus previous element if is the first one', () => {\n      const wrapper = shallowMount(RichSelectTriggerTagsTag, {\n        global,\n        props,\n      });\n\n      const parentElement = document.createElement('div');\n      [\n        wrapper.vm.$el,\n        document.createElement('button'),\n        document.createElement('button'),\n      ].forEach((el) => parentElement.appendChild(el));\n\n      jest.spyOn(window.HTMLButtonElement.prototype, 'parentElement', 'get').mockReturnValue(parentElement);\n\n      const focusSpy = jest.spyOn(window.HTMLButtonElement.prototype, 'focus');\n\n      wrapper.vm.focusPrevElement();\n\n      expect(focusSpy).not.toHaveBeenCalled();\n    });\n  });\n\n  describe('unselect method', () => {\n    afterEach(() => {\n      jest.restoreAllMocks();\n    });\n\n    it('calls the toggleOption method', () => {\n      const wrapper = shallowMount(RichSelectTriggerTagsTag, {\n        global,\n        props,\n      });\n\n      wrapper.vm.unselect();\n\n      expect(toggleOptionMock).toHaveBeenCalled();\n    });\n\n    it('gets the element index', () => {\n      const wrapper = shallowMount(RichSelectTriggerTagsTag, {\n        global,\n        props,\n      });\n\n      const parentElement = document.createElement('div');\n\n      [\n        document.createElement('button'),\n        document.createElement('button'),\n        wrapper.vm.$el,\n        document.createElement('button'),\n      ].forEach((el) => parentElement.appendChild(el));\n\n      jest.spyOn(window.HTMLButtonElement.prototype, 'parentElement', 'get').mockReturnValue(parentElement);\n\n      expect(wrapper.vm.getElementIndex()).toBe(2);\n    });\n\n    it('focus the equivalent element if the index still exists after unselected', async () => {\n      const wrapper = shallowMount(RichSelectTriggerTagsTag, {\n        global,\n        props,\n      });\n\n      const parentElement = document.createElement('div');\n\n      const elToFocus = document.createElement('button');\n\n      [\n        document.createElement('button'),\n        document.createElement('button'),\n        elToFocus,\n      ].forEach((el) => parentElement.appendChild(el));\n\n      jest.spyOn(window.HTMLButtonElement.prototype, 'parentElement', 'get').mockReturnValue(parentElement);\n      jest.spyOn(wrapper.vm, 'getElementIndex').mockReturnValue(2);\n\n      const focusSpy = jest.spyOn(elToFocus, 'focus');\n\n      wrapper.vm.unselect();\n\n      await wrapper.vm.$nextTick();\n\n      expect(focusSpy).toHaveBeenCalled();\n    });\n    it('focus the prev element element if the index doesnt exist anymore after unselected', async () => {\n      const wrapper = shallowMount(RichSelectTriggerTagsTag, {\n        global,\n        props,\n      });\n\n      const parentElement = document.createElement('div');\n\n      const elToFocus = document.createElement('button');\n\n      [\n        document.createElement('button'),\n        elToFocus,\n      ].forEach((el) => parentElement.appendChild(el));\n\n      jest.spyOn(window.HTMLButtonElement.prototype, 'parentElement', 'get').mockReturnValue(parentElement);\n      jest.spyOn(wrapper.vm, 'getElementIndex').mockReturnValue(2);\n\n      const focusSpy = jest.spyOn(elToFocus, 'focus');\n\n      wrapper.vm.unselect();\n\n      await wrapper.vm.$nextTick();\n\n      expect(focusSpy).toHaveBeenCalled();\n    });\n\n    it('doesnt focus anything if no option left to focus', async () => {\n      const wrapper = shallowMount(RichSelectTriggerTagsTag, {\n        global,\n        props,\n      });\n\n      const parentElement = document.createElement('div');\n\n      jest.spyOn(window.HTMLButtonElement.prototype, 'parentElement', 'get').mockReturnValue(parentElement);\n\n      jest.spyOn(wrapper.vm, 'getElementIndex').mockReturnValue(0);\n\n      const focusSpy = jest.spyOn(window.HTMLButtonElement.prototype, 'focus');\n\n      wrapper.vm.unselect();\n\n      await wrapper.vm.$nextTick();\n\n      expect(focusSpy).not.toHaveBeenCalled();\n    });\n  });\n\n  describe('data-value attribute', () => {\n    it('adds the data-value attribute', () => {\n      const wrapper = shallowMount(RichSelectTriggerTagsTag, {\n        global,\n        props,\n      });\n\n      expect(wrapper.vm.$el.dataset.value).toBe('a');\n    });\n\n    it('returns the value stringified if is an object', () => {\n      const wrapper = shallowMount(RichSelectTriggerTagsTag, {\n        global,\n        props: {\n          option: {\n            value: { foo: 'bar' },\n            text: 'Foo Bar',\n          },\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\n        } as any,\n      });\n\n      expect(wrapper.vm.dataValueAttribute).toEqual('{\"foo\":\"bar\"}');\n    });\n\n    it('returns the value as string if is not an object', () => {\n      const wrapper = shallowMount(RichSelectTriggerTagsTag, {\n        global,\n        props: {\n          option: {\n            value: 3,\n            text: 'Foo Bar',\n          },\n        },\n      });\n\n      expect(wrapper.vm.dataValueAttribute).toBe('3');\n    });\n  });\n});\n"
  },
  {
    "path": "src/__tests/components/TRichSelect.spec.ts",
    "content": "/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { NormalizedOption, normalizeOptions } from '@variantjs/core';\nimport { mount, shallowMount } from '@vue/test-utils';\nimport TRichSelect from '../../components/TRichSelect.vue';\nimport {\n  componentHasAttributeWithInlineHandlerAndParameter,\n  componentHasAttributeWithValue,\n  getChildComponentNameByRef,\n} from '../testUtils';\n\ndescribe('TRichSelect.vue', () => {\n  const focusDropdownTriggerMock = jest.fn();\n  const adjustPopperMock = jest.fn();\n  const dropdownDoHideMock = jest.fn();\n  const dropdownDoShowMock = jest.fn();\n\n  const TDropdownComponentMock = {\n    template: '<div />',\n    methods: {\n      focus: focusDropdownTriggerMock,\n      adjustPopper: adjustPopperMock,\n      doHide: dropdownDoHideMock,\n      doShow: dropdownDoShowMock,\n    },\n  };\n\n  afterEach(() => {\n    focusDropdownTriggerMock.mockReset();\n    adjustPopperMock.mockReset();\n    dropdownDoHideMock.mockReset();\n    dropdownDoShowMock.mockReset();\n  });\n\n  it('renders the component', () => {\n    const wrapper = shallowMount(TRichSelect);\n    expect(wrapper.get('div')).toBeTruthy();\n  });\n\n  it('hides the dropdown and focus the trigger when the vmodel value changes and the `closeOnSelect` option is set', async () => {\n    const options = [1, 2];\n    const wrapper = shallowMount(TRichSelect, {\n      props: {\n        options,\n        modelValue: 1,\n        closeOnSelect: true,\n      },\n      global: {\n        stubs: {\n          TDropdown: TDropdownComponentMock,\n        },\n      },\n    });\n\n    wrapper.vm.shown = true;\n\n    await wrapper.vm.$nextTick();\n\n    await wrapper.setProps({\n      modelValue: 2,\n    });\n\n    expect(dropdownDoHideMock).toHaveBeenCalled();\n    expect(focusDropdownTriggerMock).toHaveBeenCalled();\n  });\n\n  it('hides the dropdown and focus the trigger when the vmodel value changes and the `closeOnSelect` is undefined and is not multiple', async () => {\n    const options = [1, 2];\n    const wrapper = shallowMount(TRichSelect, {\n      props: {\n        options,\n        modelValue: 1,\n        closeOnSelect: undefined,\n        multiple: false,\n      },\n      global: {\n        stubs: {\n          TDropdown: TDropdownComponentMock,\n        },\n      },\n    });\n\n    wrapper.vm.shown = true;\n\n    await wrapper.vm.$nextTick();\n\n    await wrapper.setProps({\n      modelValue: 2,\n    });\n\n    expect(dropdownDoHideMock).toHaveBeenCalled();\n    expect(focusDropdownTriggerMock).toHaveBeenCalled();\n  });\n\n  it('doesnt hide the dropdown and focus the trigger when the vmodel value changes and the `closeOnSelect` is undefined but is multiple', async () => {\n    const options = [1, 2];\n    const wrapper = shallowMount(TRichSelect, {\n      props: {\n        options,\n        modelValue: 1,\n        closeOnSelect: undefined,\n        multiple: true,\n      },\n      global: {\n        stubs: {\n          TDropdown: TDropdownComponentMock,\n        },\n      },\n    });\n\n    wrapper.vm.shown = true;\n\n    await wrapper.vm.$nextTick();\n\n    await wrapper.setProps({\n      modelValue: 2,\n    });\n\n    expect(dropdownDoHideMock).not.toHaveBeenCalled();\n    expect(focusDropdownTriggerMock).not.toHaveBeenCalled();\n  });\n\n  it('doesnt hide the dropdown and focus the trigger when the vmodel value changes, is not multiple but closeOnSelect is `false`', async () => {\n    const options = [1, 2];\n    const wrapper = shallowMount(TRichSelect, {\n      props: {\n        options,\n        modelValue: 1,\n        closeOnSelect: false,\n        multiple: false,\n      },\n      global: {\n        stubs: {\n          TDropdown: TDropdownComponentMock,\n        },\n      },\n    });\n\n    wrapper.vm.shown = true;\n\n    await wrapper.vm.$nextTick();\n\n    await wrapper.setProps({\n      modelValue: 2,\n    });\n\n    expect(dropdownDoHideMock).not.toHaveBeenCalled();\n    expect(focusDropdownTriggerMock).not.toHaveBeenCalled();\n  });\n\n  it('has default dropdownPopperOptions', () => {\n    const wrapper = shallowMount(TRichSelect);\n\n    expect(Object.keys(wrapper.vm.dropdownPopperOptions)).toEqual([\n      'placement',\n      'modifiers',\n      'strategy',\n      'onFirstUpdate',\n    ]);\n  });\n\n  describe('provides the data needed on the child elements', () => {\n    it('provides the configuration', () => {\n      const wrapper = shallowMount(TRichSelect);\n\n      expect((wrapper.vm.$ as any).provides.configuration).toEqual(\n        (wrapper.vm.$ as any).setupState.configuration,\n      );\n    });\n\n    it('provides the options', () => {\n      const options = [1, 2, 3];\n      const wrapper = shallowMount(TRichSelect, {\n        props: {\n          options,\n        },\n      });\n\n      expect((wrapper.vm.$ as any).provides.options.value).toEqual(\n        normalizeOptions(options),\n      );\n    });\n\n    it('provides the shown state', () => {\n      const options = [1, 2, 3];\n      const wrapper = shallowMount(TRichSelect, {\n        props: {\n          options,\n        },\n      });\n\n      expect((wrapper.vm.$ as any).provides.state).toEqual(\n        (wrapper.vm.$ as any).setupState.state,\n      );\n    });\n\n    it('provides the `selectedOption` state', () => {\n      const options = [1];\n      const wrapper = shallowMount(TRichSelect, {\n        props: {\n          options,\n          modelValue: 1,\n        },\n      });\n\n      expect((wrapper.vm.$ as any).provides.selectedOption.value).toEqual({\n        value: 1,\n        text: 1,\n        raw: 1,\n      });\n    });\n\n    it('provides the `hasSelectedOption` computed property', () => {\n      const options = [1];\n      const wrapper = shallowMount(TRichSelect, {\n        props: {\n          options,\n          modelValue: 1,\n        },\n      });\n\n      expect((wrapper.vm.$ as any).provides.hasSelectedOption).toBeDefined();\n    });\n\n    it('provides the `toggleOption` method`', () => {\n      const wrapper = shallowMount(TRichSelect);\n\n      expect((wrapper.vm.$ as any).provides.toggleOption[0]).toEqual(\n        (wrapper.vm.$ as any).setupState.toggleOption,\n      );\n    });\n\n    it('provides the `optionIsActive` method`', () => {\n      const wrapper = shallowMount(TRichSelect);\n\n      expect((wrapper.vm.$ as any).provides.optionIsActive[0]).toEqual(\n        (wrapper.vm.$ as any).setupState.optionIsActive,\n      );\n    });\n\n    it('provides the `setActiveOption` method`', () => {\n      const wrapper = shallowMount(TRichSelect);\n\n      expect((wrapper.vm.$ as any).provides.setActiveOption[0]).toEqual(\n        (wrapper.vm.$ as any).setupState.setActiveOption,\n      );\n    });\n\n    it('provides the `dropdownBottomReachedHandler` method', () => {\n      const wrapper = shallowMount(TRichSelect);\n\n      expect(\n        (wrapper.vm.$ as any).provides.dropdownBottomReachedHandler[0],\n      ).toEqual((wrapper.vm.$ as any).setupState.dropdownBottomReachedHandler);\n    });\n\n    it('provides the `optionIsSelected` method`', () => {\n      const wrapper = shallowMount(TRichSelect);\n\n      expect((wrapper.vm.$ as any).provides.optionIsSelected).toEqual(\n        (wrapper.vm.$ as any).setupState.optionIsSelected,\n      );\n    });\n\n    it('provides the `keydownDownHandler` method`', () => {\n      const wrapper = shallowMount(TRichSelect);\n\n      expect((wrapper.vm.$ as any).provides.keydownDownHandler).toEqual(\n        (wrapper.vm.$ as any).setupState.keydownDownHandler,\n      );\n    });\n    it('provides the `keydownUpHandler` method`', () => {\n      const wrapper = shallowMount(TRichSelect);\n\n      expect((wrapper.vm.$ as any).provides.keydownUpHandler).toEqual(\n        (wrapper.vm.$ as any).setupState.keydownUpHandler,\n      );\n    });\n\n    it('provides the `keydownEnterHandler` method`', () => {\n      const wrapper = shallowMount(TRichSelect);\n\n      expect((wrapper.vm.$ as any).provides.keydownEnterHandler).toEqual(\n        (wrapper.vm.$ as any).setupState.keydownEnterHandler,\n      );\n    });\n\n    it('provides the `keydownEscHandler` method`', () => {\n      const wrapper = shallowMount(TRichSelect);\n\n      expect((wrapper.vm.$ as any).provides.keydownEscHandler).toEqual(\n        (wrapper.vm.$ as any).setupState.keydownEscHandler,\n      );\n    });\n\n    it('provides the `showSearchInput` computed property', () => {\n      const wrapper = shallowMount(TRichSelect);\n      expect((wrapper.vm.$ as any).provides.showSearchInput.value).toEqual(\n        (wrapper.vm.$ as any).setupState.showSearchInput,\n      );\n    });\n\n    it('provides the `needsMoreCharsMessage` computed property', () => {\n      const wrapper = shallowMount(TRichSelect);\n      expect(\n        (wrapper.vm.$ as any).provides.needsMoreCharsMessage.value,\n      ).toEqual('Please enter undefined or more characters');\n    });\n\n    it('provides the `searchQuery` ref', () => {\n      const wrapper = shallowMount(TRichSelect);\n      expect((wrapper.vm.$ as any).provides.searchQuery.value).toEqual(\n        (wrapper.vm.$ as any).setupState.searchQuery,\n      );\n    });\n\n    it('provides the `fetchingOptions` ref', () => {\n      const wrapper = shallowMount(TRichSelect);\n      expect((wrapper.vm.$ as any).provides.fetchingOptions.value).toBe(false);\n    });\n\n    it('provides the `fetchingMoreOptions` ref', () => {\n      const wrapper = shallowMount(TRichSelect);\n      expect((wrapper.vm.$ as any).provides.fetchingMoreOptions.value).toBe(\n        false,\n      );\n    });\n\n    it('provides the `usesTags` ref', () => {\n      const wrapper = shallowMount(TRichSelect);\n      expect((wrapper.vm.$ as any).provides.usesTags.value).toBe(false);\n    });\n  });\n\n  describe('usesTags', () => {\n    it('determines it uses tags if tags is set and is multiple', () => {\n      const wrapper = shallowMount(TRichSelect, {\n        props: {\n          tags: true,\n          multiple: true,\n        },\n      });\n\n      expect(wrapper.vm.usesTags).toBe(true);\n    });\n\n    it('determines it doesnt uses tags if tags is set but is no multiple', () => {\n      const wrapper = shallowMount(TRichSelect, {\n        props: {\n          tags: true,\n          multiple: false,\n        },\n      });\n\n      expect(wrapper.vm.usesTags).toBe(false);\n    });\n\n    it('determines it doesnt uses tags if tags is not set even if is multiple', () => {\n      const wrapper = shallowMount(TRichSelect, {\n        props: {\n          tags: false,\n          multiple: true,\n        },\n      });\n\n      expect(wrapper.vm.usesTags).toBe(false);\n    });\n\n    it('uses a button for the dropdown trigger if not uses tags', () => {\n      const wrapper = shallowMount(TRichSelect, {\n        props: {\n          tags: false,\n        },\n      });\n\n      expect((wrapper.vm.$refs.dropdownComponent as any).tagName).toBe(\n        'button',\n      );\n    });\n\n    it('uses a div for the dropdown trigger if uses tags', () => {\n      const wrapper = shallowMount(TRichSelect, {\n        props: {\n          tags: true,\n          multiple: true,\n        },\n      });\n\n      expect((wrapper.vm.$refs.dropdownComponent as any).tagName).toBe('div');\n    });\n  });\n\n  describe('selectedOption', () => {\n    it('sets the selectedOption from the initial v-model ', () => {\n      const options = [1, 2, 3];\n      const modelValue = 2;\n\n      const wrapper = shallowMount(TRichSelect, {\n        props: {\n          options,\n          modelValue,\n        },\n      });\n\n      expect((wrapper.vm.$ as any).provides.selectedOption.value).toEqual({\n        value: 2,\n        text: 2,\n        raw: 2,\n      });\n    });\n\n    it('sets the selectedOption from the initial v-model when not defined', () => {\n      const options = [1, 2, 3];\n\n      const wrapper = shallowMount(TRichSelect, {\n        props: {\n          options,\n        },\n      });\n\n      expect(\n        (wrapper.vm.$ as any).provides.selectedOption.value,\n      ).toBeUndefined();\n    });\n\n    it('updates the selectedOption within the v-model ', async () => {\n      const options = [1, 2, 3];\n      const modelValue = 2;\n\n      const wrapper = shallowMount(TRichSelect, {\n        props: {\n          options,\n          modelValue,\n        },\n      });\n\n      await wrapper.setProps({\n        modelValue: 3,\n      });\n\n      expect((wrapper.vm.$ as any).provides.selectedOption.value).toEqual({\n        value: 3,\n        text: 3,\n        raw: 3,\n      });\n    });\n\n    it('updates the selectedOption within the v-model when set to null ', async () => {\n      const options = [1, 2, 3];\n      const modelValue = 2;\n\n      const wrapper = shallowMount(TRichSelect, {\n        props: {\n          options,\n          modelValue,\n        },\n      });\n\n      await wrapper.setProps({\n        modelValue: null,\n      });\n\n      expect(\n        (wrapper.vm.$ as any).provides.selectedOption.value,\n      ).toBeUndefined();\n    });\n  });\n\n  describe('ClearButton', () => {\n    it('set showClearButton as `true` if `selectedOption` is clearable and is not multiple', () => {\n      const options = [1, 2, 3];\n      const modelValue = 2;\n\n      const wrapper = shallowMount(TRichSelect, {\n        props: {\n          clearable: true,\n          multiple: false,\n          options,\n          modelValue,\n        },\n      });\n\n      expect(wrapper.vm.showClearButton).toBe(true);\n    });\n\n    it('set showClearButton as `false` if `selectedOption`, is clearable but is multiple', () => {\n      const options = [1, 2, 3];\n      const modelValue = 2;\n\n      const wrapper = shallowMount(TRichSelect, {\n        props: {\n          clearable: true,\n          multiple: true,\n          options,\n          modelValue,\n        },\n      });\n\n      expect(wrapper.vm.showClearButton).toBe(false);\n    });\n\n    it('set showClearButton as `false` if `selectedOption` is multiple but is not clearable', () => {\n      const options = [1, 2, 3];\n      const modelValue = 2;\n\n      const wrapper = shallowMount(TRichSelect, {\n        props: {\n          clearable: false,\n          multiple: false,\n          options,\n          modelValue,\n        },\n      });\n\n      expect(wrapper.vm.showClearButton).toBe(false);\n    });\n\n    it('set showClearButton as `false` if no selectedOption even if is clearable and is not multiple', () => {\n      const options = [1, 2, 3];\n\n      const wrapper = shallowMount(TRichSelect, {\n        props: {\n          clearable: true,\n          multiple: false,\n          options,\n        },\n      });\n\n      expect(wrapper.vm.showClearButton).toBe(false);\n    });\n\n    it('shows the clearButton if showClearButton is `true`', () => {\n      const options = [1, 2, 3];\n      const modelValue = 2;\n\n      const wrapper = shallowMount(TRichSelect, {\n        props: {\n          clearable: true,\n          multiple: false,\n          options,\n          modelValue,\n        },\n      });\n\n      expect(wrapper.vm.$refs.clearButton).toBeDefined();\n      expect(getChildComponentNameByRef(wrapper, 'clearButton')).toEqual(\n        'RichSelectClearButton',\n      );\n    });\n\n    it('hides the clearButton if showClearButton is `false`', () => {\n      const wrapper = shallowMount(TRichSelect);\n\n      expect(wrapper.vm.$refs.clearButton).not.toBeDefined();\n    });\n\n    it('contains a `click` handler that calls the `clearValue` method', async () => {\n      const options = [1, 2, 3];\n      const modelValue = 2;\n\n      const wrapper = shallowMount(TRichSelect, {\n        props: {\n          clearable: true,\n          multiple: false,\n          options,\n          modelValue,\n        },\n      });\n\n      const component = wrapper.vm.$refs.clearButton;\n\n      expect(\n        componentHasAttributeWithValue(\n          component,\n          'onClick',\n          wrapper.vm.clearValue,\n        ),\n      ).toBe(true);\n    });\n  });\n\n  describe('event handlers', () => {\n    it.each([\n      ['onShown', 'shownHandler'],\n      ['onHidden', 'hiddenHandler'],\n      ['onBeforeShow', 'beforeShowHandler'],\n      ['onBeforeHide', 'beforeHideHandler'],\n      ['onBlur', 'blurHandler'],\n      ['onFocus', 'focusHandler'],\n      ['onMousedown', 'mousedownHandler'],\n      ['onBlurOnChild', 'blurOnChildHandler'],\n    ])(\n      'has the `%s` event handler pointing to `%s`',\n      (eventName, eventHandlerName) => {\n        const wrapper = shallowMount(TRichSelect);\n        const component = wrapper.vm.$refs.dropdownComponent as any;\n\n        expect(\n          componentHasAttributeWithValue(\n            component,\n            eventName,\n            (wrapper.vm as any)[eventHandlerName],\n          ),\n        ).toBe(true);\n      },\n    );\n\n    it('hides the dropdown with blurHandler', () => {\n      const wrapper = shallowMount(TRichSelect, {\n        global: {\n          stubs: {\n            TDropdown: TDropdownComponentMock,\n          },\n        },\n      });\n      wrapper.vm.shown = true;\n      const event = new FocusEvent('blur');\n      wrapper.vm.blurHandler(event);\n      expect(dropdownDoHideMock).toHaveBeenCalled();\n      expect(wrapper.emitted().blur).toEqual([[event]]);\n    });\n\n    describe('onOptionSelected', () => {\n      it('calls the `onOptionSelected` method when the localValue changes', async () => {\n        const options = [1, 2, 3];\n        const wrapper = shallowMount(TRichSelect, {\n          props: {\n            modelValue: 1,\n            options,\n          },\n        });\n\n        const onOptionSelectedSpy = jest.spyOn(wrapper.vm, 'onOptionSelected');\n\n        expect(onOptionSelectedSpy).not.toHaveBeenCalled();\n\n        await wrapper.setProps({\n          modelValue: 2,\n        });\n\n        expect(onOptionSelectedSpy).toHaveBeenCalled();\n      });\n\n      it('hides the dropdown and focus the dropdown if `closeOnSelect` is set to `true`', async () => {\n        const wrapper = shallowMount(TRichSelect, {\n          props: {\n            closeOnSelect: true,\n          },\n          global: {\n            stubs: {\n              TDropdown: TDropdownComponentMock,\n            },\n          },\n        });\n\n        wrapper.vm.shown = true;\n\n        wrapper.vm.onOptionSelected();\n\n        expect(dropdownDoHideMock).toHaveBeenCalled();\n        expect(focusDropdownTriggerMock).toHaveBeenCalled();\n      });\n\n      it('hides the dropdown if `closeOnSelect` is `undefined` and is not multiple', async () => {\n        const wrapper = shallowMount(TRichSelect, {\n          props: {\n            closeOnSelect: undefined,\n            multiple: false,\n          },\n          global: {\n            stubs: {\n              TDropdown: TDropdownComponentMock,\n            },\n          },\n        });\n        wrapper.vm.shown = true;\n\n        wrapper.vm.onOptionSelected();\n        expect(dropdownDoHideMock).toHaveBeenCalled();\n        expect(focusDropdownTriggerMock).toHaveBeenCalled();\n      });\n\n      it('doesnt hides the dropdown if `closeOnSelect` is `undefined` and is multiple', async () => {\n        const wrapper = shallowMount(TRichSelect, {\n          props: {\n            closeOnSelect: undefined,\n            multiple: true,\n          },\n          global: {\n            stubs: {\n              TDropdown: TDropdownComponentMock,\n            },\n          },\n        });\n\n        wrapper.vm.shown = true;\n\n        wrapper.vm.onOptionSelected();\n\n        expect(dropdownDoHideMock).not.toHaveBeenCalled();\n        expect(focusDropdownTriggerMock).not.toHaveBeenCalled();\n      });\n\n      it('doesnt hides the dropdown if is already hidden', async () => {\n        const wrapper = shallowMount(TRichSelect, {\n          props: {\n            closeOnSelect: true,\n          },\n          global: {\n            stubs: {\n              TDropdown: TDropdownComponentMock,\n            },\n          },\n        });\n\n        wrapper.vm.onOptionSelected();\n        expect(dropdownDoHideMock).not.toHaveBeenCalled();\n        expect(focusDropdownTriggerMock).not.toHaveBeenCalled();\n      });\n    });\n\n    describe('focusHandler', () => {\n      it('shows the dropdown with focusHandler when `toggleOnFocus` is set', () => {\n        const wrapper = shallowMount(TRichSelect, {\n          props: {\n            toggleOnFocus: true,\n          },\n          global: {\n            stubs: {\n              TDropdown: TDropdownComponentMock,\n            },\n          },\n        });\n        const event = new FocusEvent('focus');\n        wrapper.vm.focusHandler(event);\n        expect(dropdownDoShowMock).toHaveBeenCalled();\n        expect(wrapper.emitted().focus).toEqual([[event]]);\n      });\n\n      it('doesnt shows the dropdown with focusHandler when `toggleOnFocus` is set to `false`', () => {\n        const wrapper = shallowMount(TRichSelect, {\n          props: {\n            toggleOnFocus: false,\n          },\n          global: {\n            stubs: {\n              TDropdown: TDropdownComponentMock,\n            },\n          },\n        });\n        const event = new FocusEvent('focus');\n        wrapper.vm.focusHandler(event);\n        expect(wrapper.vm.shown).toBe(false);\n        expect(dropdownDoShowMock).not.toHaveBeenCalled();\n        expect(wrapper.emitted().focus).toEqual([[event]]);\n      });\n    });\n\n    describe('mousedownHandler', () => {\n      it('shows the dropdown when `toggleOnClick` is set', () => {\n        const wrapper = shallowMount(TRichSelect, {\n          props: {\n            toggleOnClick: true,\n          },\n          global: {\n            stubs: {\n              TDropdown: TDropdownComponentMock,\n            },\n          },\n        });\n        const event = new MouseEvent('click');\n        const preventDefaultSpy = jest.spyOn(event, 'preventDefault');\n        wrapper.vm.mousedownHandler(event);\n        expect(dropdownDoShowMock).toHaveBeenCalled();\n        expect(wrapper.emitted().mousedown).toEqual([[event]]);\n        expect(preventDefaultSpy).toHaveBeenCalled();\n      });\n\n      it('doesnt shows the dropdown when `toggleOnClick` is not set', () => {\n        const wrapper = shallowMount(TRichSelect, {\n          props: {\n            toggleOnClick: false,\n          },\n          global: {\n            stubs: {\n              TDropdown: TDropdownComponentMock,\n            },\n          },\n        });\n        const event = new MouseEvent('click');\n        const preventDefaultSpy = jest.spyOn(event, 'preventDefault');\n        wrapper.vm.mousedownHandler(event);\n        expect(dropdownDoShowMock).not.toHaveBeenCalled();\n        expect(wrapper.emitted().mousedown).toEqual([[event]]);\n        expect(preventDefaultSpy).not.toHaveBeenCalled();\n      });\n\n      it('doesnt call the `preventDefault` method if search box is hidden', () => {\n        const wrapper = shallowMount(TRichSelect, {\n          props: {\n            toggleOnClick: true,\n            hideSearchBox: true,\n          },\n          global: {\n            stubs: {\n              TDropdown: TDropdownComponentMock,\n            },\n          },\n        });\n        const event = new MouseEvent('click');\n        const preventDefaultSpy = jest.spyOn(event, 'preventDefault');\n        wrapper.vm.mousedownHandler(event);\n        expect(preventDefaultSpy).not.toHaveBeenCalled();\n      });\n\n      it('hides the dropdown when `toggleOnClick` is set and dropdown is shown', () => {\n        const wrapper = shallowMount(TRichSelect, {\n          props: {\n            toggleOnClick: true,\n          },\n          global: {\n            stubs: {\n              TDropdown: TDropdownComponentMock,\n            },\n          },\n        });\n        wrapper.vm.shown = true;\n        const event = new MouseEvent('click');\n        const preventDefaultSpy = jest.spyOn(event, 'preventDefault');\n        wrapper.vm.mousedownHandler(event);\n        expect(dropdownDoHideMock).toHaveBeenCalled();\n        expect(wrapper.emitted().mousedown).toEqual([[event]]);\n        expect(preventDefaultSpy).not.toHaveBeenCalled();\n      });\n\n      it('doesnt hides the dropdown when `toggleOnClick` is not set', () => {\n        const wrapper = shallowMount(TRichSelect, {\n          props: {\n            toggleOnClick: false,\n          },\n        });\n        wrapper.vm.shown = true;\n        const event = new MouseEvent('click');\n        const preventDefaultSpy = jest.spyOn(event, 'preventDefault');\n        wrapper.vm.mousedownHandler(event);\n        expect(wrapper.vm.shown).toBe(true);\n        expect(dropdownDoHideMock).not.toHaveBeenCalled();\n        expect(wrapper.emitted().mousedown).toEqual([[event]]);\n        expect(preventDefaultSpy).not.toHaveBeenCalled();\n      });\n    });\n\n    describe('blurOnChildHandler', () => {\n      it('will restore the original focus when blurred from the focusable item to a child not focusable element', () => {\n        const wrapper = shallowMount(TRichSelect);\n        wrapper.vm.shown = true;\n\n        const target = document.createElement('DIV');\n        const relatedTarget = document.createElement('DIV');\n\n        target.setAttribute('data-rich-select-focusable', 'true');\n        const focusSpy = jest.spyOn(target, 'focus');\n\n        wrapper.vm.blurOnChildHandler({\n          target,\n          relatedTarget,\n        } as unknown as FocusEvent);\n        expect(focusSpy).toHaveBeenCalled();\n        expect(wrapper.vm.shown).toBe(true);\n      });\n\n      it('will not restore the original focus when blurred between two focusable childs', () => {\n        const wrapper = shallowMount(TRichSelect);\n        wrapper.vm.shown = true;\n\n        const target = document.createElement('DIV');\n        target.setAttribute('data-rich-select-focusable', 'true');\n\n        const relatedTarget = document.createElement('DIV');\n        relatedTarget.setAttribute('data-rich-select-focusable', 'true');\n\n        const focusSpy = jest.spyOn(target, 'focus');\n\n        wrapper.vm.blurOnChildHandler({\n          target,\n          relatedTarget,\n        } as unknown as FocusEvent);\n        expect(focusSpy).not.toHaveBeenCalled();\n        expect(wrapper.vm.shown).toBe(true);\n      });\n\n      it('will not restore the original focus when blurred to an undefined item', () => {\n        const wrapper = shallowMount(TRichSelect);\n        wrapper.vm.shown = true;\n\n        const target = document.createElement('DIV');\n        target.setAttribute('data-rich-select-focusable', 'true');\n\n        const focusSpy = jest.spyOn(target, 'focus');\n\n        wrapper.vm.blurOnChildHandler({\n          target,\n          relatedTarget: undefined,\n        } as unknown as FocusEvent);\n        expect(focusSpy).not.toHaveBeenCalled();\n        expect(wrapper.vm.shown).toBe(true);\n      });\n    });\n\n    describe('shownHandler', () => {\n      it('sets shown as true when called', () => {\n        const wrapper = shallowMount(TRichSelect);\n        expect(wrapper.vm.shown).toBe(false);\n        wrapper.vm.shownHandler();\n        expect(wrapper.vm.shown).toBe(true);\n        expect(wrapper.emitted()).toHaveProperty('shown');\n      });\n    });\n\n    describe('hiddenHandler', () => {\n      it('sets shown as false when called', () => {\n        const wrapper = shallowMount(TRichSelect);\n        wrapper.vm.shown = true;\n        wrapper.vm.hiddenHandler();\n        expect(wrapper.vm.shown).toBe(false);\n        expect(wrapper.emitted()).toHaveProperty('hidden');\n      });\n    });\n\n    describe('beforeShowHandler', () => {\n      it('sets active option when is about to show the dropdown', () => {\n        const wrapper = shallowMount(TRichSelect);\n        const initActiveOptionSpy = jest.spyOn(\n          (wrapper.vm.$ as any).setupState,\n          'initActiveOption',\n        );\n        wrapper.vm.beforeShowHandler();\n        expect(initActiveOptionSpy).toHaveBeenCalled();\n        expect(wrapper.emitted()).toHaveProperty('before-show');\n      });\n    });\n\n    describe('beforeHideHandler', () => {\n      it('selects the active option if `selectOnclose` is set and active option is different to selected option', () => {\n        const options = [1, 2];\n        const wrapper = shallowMount(TRichSelect, {\n          props: {\n            modelValue: 1,\n            options,\n            selectOnClose: true,\n          },\n        });\n\n        wrapper.vm.activeOption = {\n          value: 2,\n          text: 2,\n          raw: 2,\n        } as NormalizedOption;\n\n        const selectOptionFromActiveOptionSpy = jest.spyOn(\n          (wrapper.vm.$ as any).setupState,\n          'selectOptionFromActiveOption',\n        );\n        wrapper.vm.beforeHideHandler();\n        expect(selectOptionFromActiveOptionSpy).toHaveBeenCalled();\n        expect(wrapper.emitted()).toHaveProperty('before-hide');\n      });\n\n      it('selects the active option if `selectOnclose` when active option is null', () => {\n        const options = [1, 2];\n        const wrapper = shallowMount(TRichSelect, {\n          props: {\n            modelValue: 1,\n            options,\n            selectOnClose: true,\n          },\n        });\n\n        wrapper.vm.activeOption = null;\n\n        const selectOptionFromActiveOptionSpy = jest.spyOn(\n          (wrapper.vm.$ as any).setupState,\n          'selectOptionFromActiveOption',\n        );\n        wrapper.vm.beforeHideHandler();\n        expect(selectOptionFromActiveOptionSpy).toHaveBeenCalled();\n        expect(wrapper.emitted()).toHaveProperty('before-hide');\n      });\n\n      it('doesnt selects the active option if `selectOnclose` is set to `false`\u001b', () => {\n        const options = [1, 2];\n        const wrapper = shallowMount(TRichSelect, {\n          props: {\n            modelValue: 1,\n            options,\n            selectOnClose: false,\n          },\n        });\n\n        wrapper.vm.activeOption = {\n          value: 2,\n          text: 2,\n          raw: 2,\n        } as NormalizedOption;\n\n        const selectOptionFromActiveOptionSpy = jest.spyOn(\n          (wrapper.vm.$ as any).setupState,\n          'selectOptionFromActiveOption',\n        );\n        wrapper.vm.beforeHideHandler();\n        expect(selectOptionFromActiveOptionSpy).not.toHaveBeenCalled();\n        expect(wrapper.emitted()).toHaveProperty('before-hide');\n      });\n\n      it('doesnt selects the active option when `selectOnclose` is set if active the same as the selected option', () => {\n        const options = [1, 2];\n        const wrapper = shallowMount(TRichSelect, {\n          props: {\n            modelValue: 2,\n            options,\n            selectOnClose: true,\n          },\n        });\n\n        wrapper.vm.activeOption = {\n          value: 2,\n          text: 2,\n          raw: 2,\n        } as NormalizedOption;\n\n        const selectOptionFromActiveOptionSpy = jest.spyOn(\n          (wrapper.vm.$ as any).setupState,\n          'selectOptionFromActiveOption',\n        );\n        wrapper.vm.beforeHideHandler();\n        expect(selectOptionFromActiveOptionSpy).not.toHaveBeenCalled();\n        expect(wrapper.emitted()).toHaveProperty('before-hide');\n      });\n    });\n  });\n\n  describe('Dropdown stuff', () => {\n    it('invalidates invalid dropdown placements', () => {\n      const { validator } = TRichSelect.props.dropdownPlacement;\n      expect(validator('invalid')).toBe(false);\n    });\n\n    it.each([\n      'auto',\n      'auto-start',\n      'auto-end',\n      'top',\n      'top-start',\n      'top-end',\n      'bottom',\n      'bottom-start',\n      'bottom-end',\n      'right',\n      'right-start',\n      'right-end',\n      'left',\n      'left-start',\n      'left-end',\n    ])('accept valid dropdown placements', (placement) => {\n      const { validator } = TRichSelect.props.dropdownPlacement;\n      expect(validator(placement)).toBe(true);\n    });\n\n    it.each([\n      ['onMouseover', 'mouseover'],\n      ['onMouseleave', 'mouseleave'],\n      ['onTouchstart', 'touchstart'],\n    ])('re-emits the event `%s`', (eventName, parameterName) => {\n      const wrapper = shallowMount(TRichSelect);\n      const component = wrapper.vm.$refs.dropdownComponent as any;\n\n      expect(\n        componentHasAttributeWithInlineHandlerAndParameter(\n          component,\n          eventName,\n          parameterName,\n        ),\n      ).toBe(true);\n    });\n\n    it.each(['mouseover', 'mouseleave'])(\n      're-emits dropdown events',\n      (eventName) => {\n        const wrapper = shallowMount(TRichSelect);\n        const component = wrapper.vm.$refs.dropdownComponent as any;\n\n        const event = new MouseEvent(eventName);\n        component.$el.dispatchEvent(event);\n\n        expect(wrapper.emitted()).toHaveProperty(eventName);\n        expect(wrapper.emitted()[eventName][0]).toEqual([event]);\n      },\n    );\n\n    it('re-emits dropdown touchstart event', () => {\n      const wrapper = shallowMount(TRichSelect);\n      const component = wrapper.vm.$refs.dropdownComponent as any;\n\n      const event = new TouchEvent('touchstart');\n      component.$el.dispatchEvent(event);\n\n      expect(wrapper.emitted()).toHaveProperty('touchstart');\n      expect(wrapper.emitted().touchstart[0]).toEqual([event]);\n    });\n\n    describe('esc key', () => {\n      it('hides the dropdown and focus the trigger when pressed esc', async () => {\n        const wrapper = shallowMount(TRichSelect, {\n          global: {\n            stubs: {\n              TDropdown: TDropdownComponentMock,\n            },\n          },\n        });\n\n        wrapper.vm.shown = true;\n\n        const dropdownComponent = wrapper.vm.$refs.dropdownComponent as any;\n\n        const event = new KeyboardEvent('keydown', { key: 'Escape' });\n        dropdownComponent.$el.dispatchEvent(event);\n\n        expect(dropdownDoHideMock).toHaveBeenCalled();\n        expect(focusDropdownTriggerMock).toHaveBeenCalled();\n        expect(wrapper.emitted()).toHaveProperty('keydown');\n        expect(wrapper.emitted().keydown[0]).toEqual([event]);\n      });\n\n      it('only re-emits the keyboard event when dropdown is closed ', async () => {\n        const wrapper = shallowMount(TRichSelect, {\n          global: {\n            stubs: {\n              TDropdown: TDropdownComponentMock,\n            },\n          },\n        });\n\n        const dropdownComponent = wrapper.vm.$refs.dropdownComponent as any;\n\n        const event = new KeyboardEvent('keydown', { key: 'Escape' });\n        dropdownComponent.$el.dispatchEvent(event);\n\n        expect(wrapper.vm.shown).toBe(false);\n        expect(focusDropdownTriggerMock).not.toHaveBeenCalled();\n        expect(wrapper.emitted()).toHaveProperty('keydown');\n        expect(wrapper.emitted().keydown[0]).toEqual([event]);\n      });\n    });\n\n    describe('space key', () => {\n      it('shows the dropdown if `toggleOnClick` is set', async () => {\n        const wrapper = shallowMount(TRichSelect, {\n          props: {\n            toggleOnClick: true,\n          },\n          global: {\n            stubs: {\n              TDropdown: TDropdownComponentMock,\n            },\n          },\n        });\n\n        const dropdownComponent = wrapper.vm.$refs.dropdownComponent as any;\n\n        const event = new KeyboardEvent('keydown', {\n          key: 'Space',\n        });\n\n        const preventDefaultSpy = jest.spyOn(event, 'preventDefault');\n\n        dropdownComponent.$el.dispatchEvent(event);\n\n        expect(dropdownDoShowMock).toHaveBeenCalled();\n        expect(preventDefaultSpy).toHaveBeenCalled();\n        expect(wrapper.emitted()).toHaveProperty('keydown');\n        expect(wrapper.emitted().keydown[0]).toEqual([event]);\n      });\n\n      it('doesnt shows the dropdown if `toggleOnClick` is not set', async () => {\n        const wrapper = shallowMount(TRichSelect, {\n          props: {\n            toggleOnClick: false,\n          },\n          global: {\n            stubs: {\n              TDropdown: TDropdownComponentMock,\n            },\n          },\n        });\n\n        const dropdownComponent = wrapper.vm.$refs.dropdownComponent as any;\n\n        const event = new KeyboardEvent('keydown', {\n          key: 'Space',\n        });\n\n        const preventDefaultSpy = jest.spyOn(event, 'preventDefault');\n\n        dropdownComponent.$el.dispatchEvent(event);\n\n        expect(wrapper.vm.shown).toBe(false);\n        expect(dropdownDoShowMock).not.toHaveBeenCalled();\n        expect(preventDefaultSpy).toHaveBeenCalled();\n        expect(wrapper.emitted()).toHaveProperty('keydown');\n        expect(wrapper.emitted().keydown[0]).toEqual([event]);\n      });\n\n      it('toggles the active option if dropdown is shown', async () => {\n        const options = [1, 2, 3];\n        const wrapper = shallowMount(TRichSelect, {\n          props: {\n            options,\n          },\n        });\n\n        wrapper.vm.shown = true;\n\n        const dropdownComponent = wrapper.vm.$refs.dropdownComponent as any;\n\n        const event = new KeyboardEvent('keydown', {\n          key: 'Space',\n        });\n\n        const preventDefaultSpy = jest.spyOn(event, 'preventDefault');\n\n        expect((wrapper.vm.$ as any).setupState.localValue).toBe(undefined);\n\n        dropdownComponent.$el.dispatchEvent(event);\n\n        expect((wrapper.vm.$ as any).setupState.localValue).toBe(1);\n        expect(wrapper.vm.shown).toBe(true);\n        expect(preventDefaultSpy).toHaveBeenCalled();\n        expect(wrapper.emitted()).toHaveProperty('keydown');\n        expect(wrapper.emitted().keydown[0]).toEqual([event]);\n\n        dropdownComponent.$el.dispatchEvent(event);\n\n        expect((wrapper.vm.$ as any).setupState.localValue).toBe(undefined);\n        expect(wrapper.vm.shown).toBe(true);\n      });\n\n      it('toggles the active option if dropdown is shown when no active option', async () => {\n        const wrapper = shallowMount(TRichSelect);\n\n        wrapper.vm.shown = true;\n\n        const dropdownComponent = wrapper.vm.$refs.dropdownComponent as any;\n\n        const event = new KeyboardEvent('keydown', {\n          key: 'Space',\n        });\n\n        const preventDefaultSpy = jest.spyOn(event, 'preventDefault');\n\n        dropdownComponent.$el.dispatchEvent(event);\n\n        expect(wrapper.vm.shown).toBe(true);\n        expect(preventDefaultSpy).toHaveBeenCalled();\n        expect(wrapper.emitted()).toHaveProperty('keydown');\n        expect(wrapper.emitted().keydown[0]).toEqual([event]);\n      });\n    });\n\n    describe('enter key', () => {\n      it('doesnt shows the dropdown when hidden', async () => {\n        const wrapper = shallowMount(TRichSelect, {\n          global: {\n            stubs: {\n              TDropdown: TDropdownComponentMock,\n            },\n          },\n        });\n\n        const dropdownComponent = wrapper.vm.$refs.dropdownComponent as any;\n\n        const event = new KeyboardEvent('keydown', {\n          key: 'Enter',\n        });\n\n        dropdownComponent.$el.dispatchEvent(event);\n\n        expect(wrapper.vm.shown).toBe(false);\n        expect(dropdownDoShowMock).not.toHaveBeenCalled();\n        expect(wrapper.emitted()).toHaveProperty('keydown');\n        expect(wrapper.emitted().keydown[0]).toEqual([event]);\n      });\n\n      it('toggles the active option if dropdown is shown', async () => {\n        const options = [1, 2, 3];\n        const wrapper = shallowMount(TRichSelect, {\n          props: {\n            options,\n          },\n        });\n\n        wrapper.vm.shown = true;\n\n        const dropdownComponent = wrapper.vm.$refs.dropdownComponent as any;\n\n        const event = new KeyboardEvent('keydown', {\n          key: 'Enter',\n        });\n\n        expect((wrapper.vm.$ as any).setupState.localValue).toBe(undefined);\n\n        dropdownComponent.$el.dispatchEvent(event);\n\n        expect((wrapper.vm.$ as any).setupState.localValue).toBe(1);\n        expect(wrapper.vm.shown).toBe(true);\n        expect(wrapper.emitted()).toHaveProperty('keydown');\n        expect(wrapper.emitted().keydown[0]).toEqual([event]);\n\n        dropdownComponent.$el.dispatchEvent(event);\n\n        expect((wrapper.vm.$ as any).setupState.localValue).toBe(undefined);\n        expect(wrapper.vm.shown).toBe(true);\n      });\n\n      it('toggles the active option if dropdown is shown when no active option', async () => {\n        const wrapper = shallowMount(TRichSelect);\n\n        wrapper.vm.shown = true;\n\n        const dropdownComponent = wrapper.vm.$refs.dropdownComponent as any;\n\n        const event = new KeyboardEvent('keydown', {\n          key: 'Enter',\n        });\n\n        dropdownComponent.$el.dispatchEvent(event);\n\n        expect(wrapper.vm.shown).toBe(true);\n        expect(wrapper.emitted()).toHaveProperty('keydown');\n        expect(wrapper.emitted().keydown[0]).toEqual([event]);\n      });\n    });\n\n    describe('key up key', () => {\n      it('shows the dropdown if hidden', async () => {\n        const wrapper = shallowMount(TRichSelect, {\n          props: {\n            toggleOnClick: true,\n          },\n          global: {\n            stubs: {\n              TDropdown: TDropdownComponentMock,\n            },\n          },\n        });\n\n        const dropdownComponent = wrapper.vm.$refs.dropdownComponent as any;\n\n        const event = new KeyboardEvent('keydown', {\n          key: 'ArrowUp',\n        });\n\n        const preventDefaultSpy = jest.spyOn(event, 'preventDefault');\n\n        dropdownComponent.$el.dispatchEvent(event);\n\n        expect(dropdownDoShowMock).toHaveBeenCalled();\n        expect(preventDefaultSpy).toHaveBeenCalled();\n        expect(wrapper.emitted()).toHaveProperty('keydown');\n        expect(wrapper.emitted().keydown[0]).toEqual([event]);\n      });\n\n      it('activates the the prev option if dropdown is shown', async () => {\n        const options = [1, 2, 3];\n        const wrapper = shallowMount(TRichSelect, {\n          props: {\n            options,\n            toggleOnClick: true,\n          },\n        });\n        wrapper.vm.shown = true;\n        wrapper.vm.activeOption = {\n          value: 3,\n          text: 3,\n          raw: 3,\n        } as NormalizedOption;\n\n        const dropdownComponent = wrapper.vm.$refs.dropdownComponent as any;\n\n        const event = new KeyboardEvent('keydown', {\n          key: 'ArrowUp',\n        });\n\n        const preventDefaultSpy = jest.spyOn(event, 'preventDefault');\n\n        dropdownComponent.$el.dispatchEvent(event);\n\n        expect(wrapper.vm.shown).toBe(true);\n        expect(wrapper.vm.activeOption).toEqual({\n          value: 2,\n          text: 2,\n          raw: 2,\n        } as NormalizedOption);\n        expect(preventDefaultSpy).toHaveBeenCalled();\n        expect(wrapper.emitted()).toHaveProperty('keydown');\n        expect(wrapper.emitted().keydown[0]).toEqual([event]);\n      });\n    });\n\n    describe('key down key', () => {\n      it('shows the dropdown if hidden', async () => {\n        const wrapper = shallowMount(TRichSelect, {\n          props: {\n            toggleOnClick: true,\n          },\n          global: {\n            stubs: {\n              TDropdown: TDropdownComponentMock,\n            },\n          },\n        });\n\n        const dropdownComponent = wrapper.vm.$refs.dropdownComponent as any;\n\n        const event = new KeyboardEvent('keydown', {\n          key: 'ArrowDown',\n        });\n\n        const preventDefaultSpy = jest.spyOn(event, 'preventDefault');\n\n        dropdownComponent.$el.dispatchEvent(event);\n\n        expect(dropdownDoShowMock).toHaveBeenCalled();\n        expect(preventDefaultSpy).toHaveBeenCalled();\n        expect(wrapper.emitted()).toHaveProperty('keydown');\n        expect(wrapper.emitted().keydown[0]).toEqual([event]);\n      });\n\n      it('activates the the next option if dropdown is shown', async () => {\n        const options = [1, 2, 3];\n        const wrapper = shallowMount(TRichSelect, {\n          props: {\n            options,\n            toggleOnClick: true,\n          },\n        });\n        wrapper.vm.shown = true;\n\n        const dropdownComponent = wrapper.vm.$refs.dropdownComponent as any;\n\n        const event = new KeyboardEvent('keydown', {\n          key: 'ArrowDown',\n        });\n\n        const preventDefaultSpy = jest.spyOn(event, 'preventDefault');\n\n        dropdownComponent.$el.dispatchEvent(event);\n\n        expect(wrapper.vm.shown).toBe(true);\n        expect(wrapper.vm.activeOption).toEqual({\n          value: 2,\n          text: 2,\n          raw: 2,\n        } as NormalizedOption);\n        expect(preventDefaultSpy).toHaveBeenCalled();\n        expect(wrapper.emitted()).toHaveProperty('keydown');\n        expect(wrapper.emitted().keydown[0]).toEqual([event]);\n      });\n\n      it('calls the fetchMoreOptions method if press down, is last item and have more options to fetch', async () => {\n        const responsePromise = new Promise((resolve) => {\n          resolve({\n            results: [1, 2],\n            hasMorePages: true,\n          });\n        });\n        const fetchOptionsMock = jest.fn().mockReturnValue(responsePromise);\n\n        const wrapper = shallowMount(TRichSelect, {\n          props: {\n            toggleOnClick: true,\n            fetchOptions: fetchOptionsMock,\n            delay: 0,\n          },\n        });\n\n        wrapper.vm.shown = true;\n\n        const dropdownComponent = wrapper.vm.$refs.dropdownComponent as any;\n\n        const event = new KeyboardEvent('keydown', {\n          key: 'ArrowDown',\n        });\n\n        // So it calls the fetchOptions method\n        wrapper.vm.beforeShowHandler();\n\n        // Should be called with `undefined` search query and `undefined` next page.\n        expect(fetchOptionsMock).toHaveBeenLastCalledWith(undefined, undefined);\n        expect(fetchOptionsMock).toHaveBeenCalledTimes(1);\n\n        // Wait until options were fetched.\n        await wrapper.vm.$nextTick();\n        // Wait until options were stored in the state\n        await wrapper.vm.$nextTick();\n\n        // Active option is first one\n        expect(wrapper.vm.activeOption!.value).toEqual(1);\n        // Not called again yet\n        await wrapper.vm.$nextTick();\n        expect(fetchOptionsMock).toHaveBeenCalledTimes(1);\n\n        // Press down one time\n        dropdownComponent.$el.dispatchEvent(event);\n        // now the active option is last loaded one\n        expect(wrapper.vm.activeOption!.value).toEqual(2);\n        await wrapper.vm.$nextTick();\n        // Called again\n        expect(fetchOptionsMock).toHaveBeenCalledTimes(2);\n        // No search query but page 2\n        expect(fetchOptionsMock).toHaveBeenLastCalledWith(undefined, 2);\n      });\n\n      it('doesnt calls the fetchMoreOptions method if press down if is last item if no have more options to fetch', async () => {\n        const responsePromise = new Promise((resolve) => {\n          resolve({\n            results: [1, 2],\n          });\n        });\n        const fetchOptionsMock = jest.fn().mockReturnValue(responsePromise);\n\n        const wrapper = shallowMount(TRichSelect, {\n          props: {\n            toggleOnClick: true,\n            fetchOptions: fetchOptionsMock,\n            delay: 0,\n          },\n        });\n\n        wrapper.vm.shown = true;\n\n        const dropdownComponent = wrapper.vm.$refs.dropdownComponent as any;\n\n        const event = new KeyboardEvent('keydown', {\n          key: 'ArrowDown',\n        });\n\n        // So it calls the fetchOptions method\n        wrapper.vm.beforeShowHandler();\n\n        // Should be called with `undefined` search query and `undefined` next page.\n        expect(fetchOptionsMock).toHaveBeenLastCalledWith(undefined, undefined);\n        expect(fetchOptionsMock).toHaveBeenCalledTimes(1);\n\n        // Wait until options were fetched.\n        await wrapper.vm.$nextTick();\n        // Wait until options were stored in the state\n        await wrapper.vm.$nextTick();\n\n        // Active option is first one\n        expect(wrapper.vm.activeOption!.value).toEqual(1);\n        // Not called again yet\n        await wrapper.vm.$nextTick();\n        expect(fetchOptionsMock).toHaveBeenCalledTimes(1);\n\n        // Press down one time\n        dropdownComponent.$el.dispatchEvent(event);\n        // now the active option is last loaded one\n        expect(wrapper.vm.activeOption!.value).toEqual(2);\n        await wrapper.vm.$nextTick();\n        // But it not calls the fetchOptions method\n        expect(fetchOptionsMock).toHaveBeenCalledTimes(1);\n      });\n\n      it('doesnt calls the fetchMoreOptions method if press down if is currently loading more options', async () => {\n        const responsePromise1 = new Promise((resolve) => {\n          resolve({\n            results: [1, 2],\n            hasMorePages: true,\n          });\n        });\n        const responsePromise2 = new Promise(() => {\n          // Never resolves\n        });\n        const fetchOptionsMock = jest.fn().mockReturnValue(responsePromise1);\n\n        const wrapper = shallowMount(TRichSelect, {\n          props: {\n            toggleOnClick: true,\n            fetchOptions: fetchOptionsMock,\n            delay: 0,\n          },\n        });\n\n        wrapper.vm.shown = true;\n\n        const dropdownComponent = wrapper.vm.$refs.dropdownComponent as any;\n\n        const event = new KeyboardEvent('keydown', {\n          key: 'ArrowDown',\n        });\n\n        // So it calls the fetchOptions method\n        wrapper.vm.beforeShowHandler();\n\n        // Should be called with `undefined` search query and `undefined` next page.\n        expect(fetchOptionsMock).toHaveBeenLastCalledWith(undefined, undefined);\n        expect(fetchOptionsMock).toHaveBeenCalledTimes(1);\n\n        // Wait until options were fetched.\n        await wrapper.vm.$nextTick();\n        // Wait until options were stored in the state\n        await wrapper.vm.$nextTick();\n\n        // Active option is first one\n        expect(wrapper.vm.activeOption!.value).toEqual(1);\n        // Not called again yet\n        await wrapper.vm.$nextTick();\n        expect(fetchOptionsMock).toHaveBeenCalledTimes(1);\n\n        fetchOptionsMock.mockReturnValue(responsePromise2);\n\n        // Press down one time\n        dropdownComponent.$el.dispatchEvent(event);\n        // now the active option is last loaded one\n        expect(wrapper.vm.activeOption!.value).toEqual(2);\n        await wrapper.vm.$nextTick();\n        // Called again\n        expect(fetchOptionsMock).toHaveBeenCalledTimes(2);\n        // No search query but page 2\n        expect(fetchOptionsMock).toHaveBeenLastCalledWith(undefined, 2);\n\n        // Wait until options call is resolved (that will never happen in this test\n        // to emulate a busy state)\n        await wrapper.vm.$nextTick();\n\n        // Press down one time\n        dropdownComponent.$el.dispatchEvent(event);\n\n        await wrapper.vm.$nextTick();\n        // Was not called again (still called twice) since its busy\n        expect(fetchOptionsMock).toHaveBeenCalledTimes(2);\n      });\n    });\n  });\n\n  describe('fetch options', () => {\n    it('emits a `fetch-options-success` event with the response', async () => {\n      const response = {\n        results: [1, 2],\n      };\n\n      const fetchOptions = () => new Promise((resolve) => {\n        resolve(response);\n      });\n\n      const wrapper = shallowMount(TRichSelect, {\n        props: {\n          fetchOptions,\n          delay: 0,\n        } as any,\n      });\n\n      (wrapper.vm.$ as any).setupState.doFetchOptions();\n\n      await wrapper.vm.$nextTick();\n\n      await wrapper.vm.$nextTick();\n\n      expect(wrapper.emitted('fetch-options-success')).toEqual([[response]]);\n    });\n\n    it('emits a `fetch-options-error` event when an exception occurs', async () => {\n      const error = new Error('test');\n\n      const fetchOptions = () => new Promise((_resolve, reject) => {\n        reject(error);\n      });\n\n      const wrapper = shallowMount(TRichSelect, {\n        props: {\n          fetchOptions,\n          delay: 0,\n        } as any,\n      });\n\n      (wrapper.vm.$ as any).setupState.doFetchOptions();\n\n      await wrapper.vm.$nextTick();\n\n      await wrapper.vm.$nextTick();\n\n      expect(wrapper.emitted('fetch-options-error')).toEqual([[error]]);\n    });\n  });\n\n  describe('prefetch options', () => {\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    let prefetchOptionsSpy: any;\n    const originalCreatedMethod = TRichSelect.created!;\n\n    beforeEach(() => {\n      // eslint-disable-next-line func-names\n      TRichSelect.created = function () {\n        // this.$.setupState.doFetchOptions =\n        prefetchOptionsSpy = jest.spyOn(this.$.setupState, 'doPrefetchOptions');\n\n        originalCreatedMethod.call(this);\n      };\n    });\n\n    afterEach(() => {\n      jest.restoreAllMocks();\n\n      TRichSelect.created = originalCreatedMethod;\n    });\n\n    it('fetch the options when prefetchOptions option is set', () => {\n      shallowMount(TRichSelect, {\n        props: {\n          fetchOptions: () => {},\n          prefetchOptions: true,\n        } as any,\n      });\n\n      expect(prefetchOptionsSpy).toHaveBeenCalled();\n    });\n\n    it('fetch the options when prefetchOptions option is set as a function', () => {\n      shallowMount(TRichSelect, {\n        props: {\n          prefetchOptions: () => Promise.resolve([]),\n        } as any,\n      });\n\n      expect(prefetchOptionsSpy).toHaveBeenCalled();\n    });\n\n    it('doesnt prefetchs the options when prefetchOptions option is set if no fetch function', () => {\n      shallowMount(TRichSelect, {\n        props: {\n          prefetchOptions: true,\n        },\n      });\n\n      expect(prefetchOptionsSpy).not.toHaveBeenCalled();\n    });\n\n    it('doesnt fetch the options when prefetchOptions option is not set', () => {\n      shallowMount(TRichSelect, {\n        props: {\n          fetchsOptions: () => {},\n          prefetchOptions: false,\n        },\n      });\n\n      expect(prefetchOptionsSpy).not.toHaveBeenCalled();\n    });\n  });\n\n  describe('fetch options when dropdown bottom reached', () => {\n    it('fetchs more options when dropdownBottomReachedHandler called if has more pages', async () => {\n      const responsePromise = new Promise((resolve) => {\n        resolve({\n          results: [1, 2],\n          hasMorePages: true,\n        });\n      });\n\n      const fetchOptionsMock = jest.fn().mockReturnValue(responsePromise);\n\n      const wrapper = shallowMount(TRichSelect, {\n        props: {\n          toggleOnClick: true,\n          fetchOptions: fetchOptionsMock,\n          delay: 0,\n        },\n      });\n\n      wrapper.vm.shown = true;\n\n      // So it calls the fetchOptions method the first time\n      wrapper.vm.beforeShowHandler();\n\n      // Should be called with `undefined` search query and `undefined` next page.\n      expect(fetchOptionsMock).toHaveBeenLastCalledWith(undefined, undefined);\n      expect(fetchOptionsMock).toHaveBeenCalledTimes(1);\n\n      // Wait until options were fetched.\n      await wrapper.vm.$nextTick();\n      // Wait until options were stored in the state\n      await wrapper.vm.$nextTick();\n\n      (wrapper.vm.$ as any).provides.dropdownBottomReachedHandler();\n\n      // Called again\n      expect(fetchOptionsMock).toHaveBeenCalledTimes(2);\n      // No search query but page 2\n      expect(fetchOptionsMock).toHaveBeenLastCalledWith(undefined, 2);\n    });\n\n    it('doesnt fetch more options when dropdownBottomReachedHandler called if no more pages', async () => {\n      const responsePromise = new Promise((resolve) => {\n        resolve({\n          results: [1, 2],\n          hasMorePages: false,\n        });\n      });\n\n      const fetchOptionsMock = jest.fn().mockReturnValue(responsePromise);\n\n      const wrapper = shallowMount(TRichSelect, {\n        props: {\n          toggleOnClick: true,\n          fetchOptions: fetchOptionsMock,\n          delay: 0,\n        },\n      });\n\n      wrapper.vm.shown = true;\n\n      // So it calls the fetchOptions method the first time\n      wrapper.vm.beforeShowHandler();\n\n      // Should be called with `undefined` search query and `undefined` next page.\n      expect(fetchOptionsMock).toHaveBeenLastCalledWith(undefined, undefined);\n      expect(fetchOptionsMock).toHaveBeenCalledTimes(1);\n\n      // Wait until options were fetched.\n      await wrapper.vm.$nextTick();\n      // Wait until options were stored in the state\n      await wrapper.vm.$nextTick();\n\n      (wrapper.vm.$ as any).provides.dropdownBottomReachedHandler();\n\n      // Still called 1 time\n      expect(fetchOptionsMock).toHaveBeenCalledTimes(1);\n    });\n\n    it('doesnt fetchs more options when dropdownBottomReachedHandler called if previous call is busy', async () => {\n      const responsePromise = new Promise((resolve) => {\n        resolve({\n          results: [1, 2],\n          hasMorePages: true,\n        });\n      });\n\n      const responsePromise2 = new Promise(() => {\n        // never resolve\n      });\n\n      const fetchOptionsMock = jest.fn().mockReturnValue(responsePromise);\n\n      const wrapper = shallowMount(TRichSelect, {\n        props: {\n          toggleOnClick: true,\n          fetchOptions: fetchOptionsMock,\n          delay: 0,\n        },\n      });\n\n      wrapper.vm.shown = true;\n\n      // So it calls the fetchOptions method the first time\n      wrapper.vm.beforeShowHandler();\n\n      // Should be called with `undefined` search query and `undefined` next page.\n      expect(fetchOptionsMock).toHaveBeenLastCalledWith(undefined, undefined);\n      expect(fetchOptionsMock).toHaveBeenCalledTimes(1);\n\n      // Wait until options were fetched.\n      await wrapper.vm.$nextTick();\n      // Wait until options were stored in the state\n      await wrapper.vm.$nextTick();\n\n      (wrapper.vm.$ as any).provides.dropdownBottomReachedHandler();\n\n      // Called again\n      expect(fetchOptionsMock).toHaveBeenCalledTimes(2);\n      // No search query but now uses page 2\n      expect(fetchOptionsMock).toHaveBeenLastCalledWith(undefined, 2);\n\n      fetchOptionsMock.mockReturnValue(responsePromise2);\n\n      (wrapper.vm.$ as any).provides.dropdownBottomReachedHandler();\n\n      // Bottom reached again but previous call is still busy\n      (wrapper.vm.$ as any).provides.dropdownBottomReachedHandler();\n\n      await wrapper.vm.$nextTick();\n      // Was not called again (still called twice) since its busy\n      expect(fetchOptionsMock).toHaveBeenCalledTimes(2);\n    });\n\n    it('calls the fetchOptionsCancel method when component unmonted', () => {\n      const wrapper = shallowMount(TRichSelect);\n\n      const cancelSpy = jest.spyOn(\n        (wrapper.vm.$ as any).setupState,\n        'fetchOptionsCancel',\n      );\n\n      wrapper.unmount();\n\n      expect(cancelSpy).toHaveBeenCalled();\n    });\n  });\n\n  describe('show search input condition', () => {\n    it('hides the search input if `hideSearchbox` is set', () => {\n      const wrapper = shallowMount(TRichSelect, {\n        props: {\n          hideSearchBox: true,\n        },\n      });\n\n      expect(wrapper.vm.showSearchInput).toBe(false);\n    });\n\n    it('hides the search input `minimumResultsForSearch` is set and we have more options than the limit', () => {\n      const wrapper = shallowMount(TRichSelect, {\n        props: {\n          options: ['1', '2', '3'],\n          minimumResultsForSearch: 4,\n        },\n      });\n\n      expect(wrapper.vm.showSearchInput).toBe(false);\n    });\n\n    it('shows the search input `minimumResultsForSearch` is set and we have the same options as the limit', () => {\n      const wrapper = shallowMount(TRichSelect, {\n        props: {\n          options: ['1', '2', '3'],\n          minimumResultsForSearch: 3,\n        },\n      });\n\n      expect(wrapper.vm.showSearchInput).toBe(true);\n    });\n\n    it('shows the search input `minimumResultsForSearch` is set and we have the more options than the limit', () => {\n      const wrapper = shallowMount(TRichSelect, {\n        props: {\n          options: ['1', '2', '3', '4'],\n          minimumResultsForSearch: 3,\n        },\n      });\n\n      expect(wrapper.vm.showSearchInput).toBe(true);\n    });\n\n    it('shows the search input if `minimumResultsForSearch` is not set and `hideSearchBox` is set to `false`', () => {\n      const wrapper = shallowMount(TRichSelect, {\n        props: {\n          hideSearchBox: false,\n        },\n      });\n\n      expect(wrapper.vm.showSearchInput).toBe(true);\n    });\n  });\n\n  describe('clear search query', () => {\n    it('doesnt clears the search when the dropdown closes by default', async () => {\n      const wrapper = shallowMount(TRichSelect);\n\n      wrapper.vm.searchQuery = 'search query';\n\n      wrapper.vm.hiddenHandler();\n\n      expect(wrapper.vm.searchQuery).toBe('search query');\n    });\n\n    it('clears the search when the dropdown closes and when `clearSearchOnClose` option is set', async () => {\n      const wrapper = shallowMount(TRichSelect, {\n        props: {\n          clearSearchOnClose: true,\n        },\n      });\n\n      wrapper.vm.searchQuery = 'search query';\n\n      wrapper.vm.hiddenHandler();\n\n      expect(wrapper.vm.searchQuery).toBeUndefined();\n    });\n  });\n\n  it('teleports the dropdown to the body if teleport option is set', async () => {\n    const wrapper = mount(TRichSelect, {\n      props: {\n        teleport: true,\n      },\n    });\n\n    wrapper.vm.toggleDropdown();\n\n    await wrapper.vm.$nextTick();\n\n    await wrapper.vm.$nextTick();\n\n    expect(document.body.children[0].textContent).toBe('No options found');\n  });\n});\n"
  },
  {
    "path": "src/__tests/components/TSelect/TSelectOption.spec.ts",
    "content": "/* eslint-disable @typescript-eslint/no-non-null-assertion */\nimport { mount, shallowMount } from '@vue/test-utils';\nimport { NormalizedOption } from '@variantjs/core';\nimport TSelectOption from '@/components/TSelect/TSelectOption.vue';\n\ndescribe('TSelectOption.vue', () => {\n  it('renders the option', () => {\n    const option: NormalizedOption = {\n      text: 'Hello World',\n      value: 'hello',\n    };\n    const wrapper = shallowMount(TSelectOption, {\n      props: {\n        option,\n      },\n    });\n    expect(wrapper.html()).toBe('<option value=\"hello\">Hello World</option>');\n  });\n  it('renders an optgroup if has children elements', () => {\n    const option: NormalizedOption = {\n      text: 'Hello World',\n      value: 'hello',\n      children: [{\n        text: 'Letter A', value: 'A',\n      }],\n    };\n    const wrapper = mount(TSelectOption, {\n      props: {\n        option,\n      },\n    });\n\n    const optGroup = wrapper.vm.$el;\n    const options = optGroup.querySelectorAll(['option']);\n    expect(optGroup.tagName).toBe('OPTGROUP');\n    expect(options).toHaveLength(1);\n    expect(options[0].value).toBe('A');\n    expect((options[0] as HTMLOptionElement).text).toBe('Letter A');\n  });\n\n  it('disables optgroup ', () => {\n    const option: NormalizedOption = {\n      text: 'Hello World',\n      value: 'hello',\n      children: [{\n        text: 'A', value: 'A',\n      }],\n      disabled: true,\n    };\n    const wrapper = shallowMount(TSelectOption, {\n      props: {\n        option,\n      },\n    });\n\n    expect(wrapper.vm.$el.disabled).toBeTruthy();\n  });\n\n  it('disables the option', () => {\n    const option: NormalizedOption = {\n      text: 'Hello World',\n      value: 'hello',\n      disabled: true,\n    };\n    const wrapper = shallowMount(TSelectOption, {\n      props: {\n        option,\n      },\n    });\n    expect(wrapper.html()).toBe('<option disabled=\"\" value=\"hello\">Hello World</option>');\n  });\n\n  it('disables the option with a `disabled` string', () => {\n    const option: NormalizedOption = {\n      text: 'Hello World',\n      value: 'hello',\n      disabled: 'disabled',\n    };\n    const wrapper = shallowMount(TSelectOption, {\n      props: {\n        option,\n      },\n    });\n\n    expect(wrapper.html()).toBe('<option disabled=\"\" value=\"hello\">Hello World</option>');\n  });\n});\n"
  },
  {
    "path": "src/__tests/components/TSelect.integration.spec.ts",
    "content": "/* eslint-disable @typescript-eslint/no-non-null-assertion */\nimport { render, fireEvent } from '@testing-library/vue';\nimport TSelect from '@/components/TSelect.vue';\n\ndescribe('TSelect.vue', () => {\n  it('handles the v-model', async () => {\n    const { container, getByDisplayValue } = render(TSelect, {\n      props: {\n        options: ['A', 'B'],\n      },\n    });\n\n    const select = container.querySelector('select')!;\n\n    await fireEvent.update(select!, 'B');\n\n    getByDisplayValue('B');\n  });\n\n  it('selects the option', async () => {\n    const { container } = render(TSelect, {\n      props: {\n        options: ['A', 'B'],\n      },\n    });\n\n    const select = container.querySelector('select')!;\n\n    expect(select.querySelectorAll('option')).toHaveLength(2);\n  });\n\n  it('contains the class + classes + fixedClasses', async () => {\n    const { container } = render(TSelect, {\n      props: {\n        fixedClasses: 'text-red-500',\n        classes: 'border-red-500',\n        class: 'font-semibold',\n      },\n    });\n\n    const select = container.querySelector('.text-red-500.border-red-500.font-semibold');\n    expect(select).not.toBeNull();\n  });\n\n  it('adds the html attributes', async () => {\n    const { getByRole, getByTitle } = render(TSelect, {\n      props: {\n        role: 'text-field',\n        title: 'my title',\n      },\n    });\n\n    getByRole('text-field');\n\n    getByTitle('my title');\n  });\n\n  it('adds the classes on the variant', async () => {\n    const { container } = render(TSelect, {\n      props: {\n        variants: {\n          error: {\n            classes: 'text-red-500',\n          },\n        },\n        variant: 'error',\n        classes: 'text-blue-500',\n      },\n    });\n\n    let select = container.querySelector('.text-red-500');\n    expect(select).not.toBeNull();\n\n    select = container.querySelector('.text-blue-500');\n    expect(select).toBeNull();\n  });\n});\n"
  },
  {
    "path": "src/__tests/components/TSelect.spec.ts",
    "content": "/* eslint-disable @typescript-eslint/no-non-null-assertion */\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport { mount, shallowMount } from '@vue/test-utils';\nimport { TSelectConfig } from '@variantjs/core';\nimport TSelect from '@/components/TSelect.vue';\n\ndescribe('TSelect.vue', () => {\n  it('renders the select', () => {\n    const wrapper = shallowMount(TSelect);\n    expect(wrapper.get('select')).toBeTruthy();\n  });\n\n  it('renders the select with a default set of classes', () => {\n    const wrapper = shallowMount(TSelect);\n\n    expect(wrapper.html()).toBe(`<select class=\"${TSelectConfig.classes}\"></select>`);\n  });\n\n  it('renders the select without attributes if no default theme', () => {\n    const wrapper = shallowMount(TSelect, {\n      global: {\n        provide: {\n          configuration: {\n            TSelect: {\n              classes: undefined,\n            },\n          },\n        },\n      },\n    });\n\n    expect(wrapper.html()).toBe('<select></select>');\n  });\n\n  it('selects the props.value', () => {\n    const value = 'B';\n    const wrapper = mount(TSelect, {\n      props: {\n        modelValue: value,\n        options: ['A', 'B', 'C'],\n      },\n    });\n\n    expect(wrapper.vm.localValue).toBe(value);\n    expect(wrapper.vm.$el.value).toEqual(value);\n  });\n\n  it('doesnt add the modelValue as attribute', () => {\n    const value = 'B';\n    const wrapper = shallowMount(TSelect, {\n      props: { modelValue: value, options: ['A', 'B', 'C'] },\n\n    });\n\n    expect(wrapper.vm.$el.attributes.modelValue).toBeUndefined();\n  });\n\n  it('adds the multiple attribute', async () => {\n    const wrapper = shallowMount(TSelect, {\n      props: { multiple: false },\n    });\n    expect(wrapper.vm.$el.multiple).toBe(false);\n\n    await wrapper.setProps({ multiple: true });\n\n    expect(wrapper.vm.$el.multiple).toBe(true);\n  });\n\n  it('handles multiptions', async () => {\n    const value = ['B', 'C'];\n    const wrapper = mount(TSelect, {\n      props: {\n        modelValue: value,\n        multiple: true,\n        options: ['A', 'B', 'C'],\n      },\n    });\n\n    const select = wrapper.vm.$el;\n\n    expect(wrapper.vm.localValue).toEqual(value);\n\n    const values = Array\n      .from(select.querySelectorAll('option:checked'))\n      .map((el) => (el as HTMLOptionElement).value);\n\n    expect(values).toEqual(value);\n\n    const newValue = ['A', 'C'];\n\n    // await wrapper.setValue(newValue, 'modelValue');\n    await wrapper.setProps({\n      modelValue: newValue,\n    });\n\n    expect(wrapper.vm.localValue).toEqual(newValue);\n\n    const newValues = Array\n      .from(select.querySelectorAll('option:checked'))\n      .map((el) => (el as HTMLOptionElement).value);\n\n    expect(newValues).toEqual(newValue);\n  });\n\n  it('assigns undefined as default', () => {\n    const wrapper = shallowMount(TSelect);\n\n    expect(wrapper.vm.localValue).toBeUndefined();\n  });\n\n  it('assigns an array as default to multiptions', () => {\n    const wrapper = shallowMount(TSelect, {\n      props: {\n        multiple: true,\n      },\n    });\n\n    expect(wrapper.vm.localValue).toEqual([]);\n  });\n\n  it('disables the select', async () => {\n    const wrapper = shallowMount(TSelect, {\n      props: { disabled: false },\n    });\n    expect(wrapper.vm.$el.disabled).toBe(false);\n\n    await wrapper.setProps({ disabled: true });\n\n    expect(wrapper.vm.$el.disabled).toBe(true);\n  });\n\n  it('accepts different attributes', async () => {\n    const wrapper = shallowMount(TSelect);\n\n    const values = {\n      id: {\n        default: '',\n        new: 'new-id',\n      },\n      autofocus: {\n        default: false,\n        new: true,\n      },\n      disabled: {\n        default: false,\n        new: true,\n      },\n      name: {\n        default: '',\n        new: 'new-name',\n      },\n      required: {\n        default: false,\n        new: true,\n      },\n    };\n\n    const select = wrapper.vm.$el;\n\n    const newProps: any = {};\n    // Check for the default values\n    Object.keys(values).forEach((key) => {\n      const elementValue = (values as any)[key];\n      expect(select[elementValue.keyName || key]).toBe(elementValue.default);\n\n      newProps[key as any] = elementValue.new;\n    });\n\n    await wrapper.setProps(newProps);\n\n    // Check for the new values\n    Object.keys(values).forEach((key) => {\n      const elementValue = (values as any)[key];\n      expect(select[elementValue.keyName || key]).toBe(elementValue.new);\n    });\n  });\n\n  it('emits an update event with the select value', () => {\n    const modelValue = 'A';\n\n    const wrapper = shallowMount(TSelect, {\n      props: {\n        modelValue,\n        options: ['A', 'B'],\n      },\n    });\n\n    const inputValue = 'B';\n\n    wrapper.setValue(inputValue);\n\n    expect(wrapper.emitted('update:modelValue')).toBeTruthy();\n\n    // assert event count\n    expect(wrapper.emitted('update:modelValue')?.length).toBe(1);\n\n    // assert event payload\n    expect(wrapper.emitted('update:modelValue')![0]).toEqual([inputValue]);\n  });\n\n  it('emits native select events', () => {\n    const onChange = jest.fn();\n    const onBlur = jest.fn();\n    const onFocus = jest.fn();\n    const onInput = jest.fn();\n\n    const wrapper = shallowMount(TSelect, {\n      attrs: {\n        onChange,\n        onBlur,\n        onFocus,\n        onInput,\n      },\n    });\n\n    const input = wrapper.vm.$el;\n\n    input.dispatchEvent(new Event('change'));\n    expect(onChange).toHaveBeenCalled();\n\n    input.dispatchEvent(new FocusEvent('focus'));\n    expect(onFocus).toHaveBeenCalled();\n\n    input.dispatchEvent(new FocusEvent('blur'));\n    expect(onBlur).toHaveBeenCalled();\n\n    input.dispatchEvent(new InputEvent('input'));\n    expect(onInput).toHaveBeenCalled();\n  });\n\n  it('has native select methods', () => {\n    const wrapper = shallowMount(TSelect);\n\n    const select = wrapper.vm.$el;\n\n    expect(typeof select.click).toBe('function');\n    expect(typeof select.focus).toBe('function');\n  });\n\n  it('triggers custom events', async () => {\n    const onCustom = jest.fn();\n\n    const wrapper = shallowMount(TSelect, {\n      attrs: {\n        onCustom,\n      },\n    });\n    const select = wrapper.vm.$el as HTMLSelectElement;\n\n    const evt = new CustomEvent('custom', { detail: 'my-custom-event' });\n    select.dispatchEvent(evt);\n\n    expect(onCustom).toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "src/__tests/components/TTag.spec.ts",
    "content": "import { shallowMount } from '@vue/test-utils';\nimport TTag from '@/components/TTag.vue';\n\ndescribe('TTag.vue', () => {\n  it('renders the component without errors', () => {\n    const wrapper = shallowMount(TTag);\n    expect(wrapper.vm.$el.tagName).toBe('DIV');\n  });\n\n  it('accepts a different tag for the wrapper', () => {\n    const wrapper = shallowMount(TTag, {\n      props: {\n        tagName: 'table',\n      },\n    });\n    expect(wrapper.vm.$el.tagName).toBe('TABLE');\n  });\n\n  it('renders the default slot content', () => {\n    const wrapper = shallowMount(TTag, {\n      slots: {\n        default: 'Im a tag!',\n      },\n    });\n\n    expect(wrapper.vm.$el.innerHTML).toBe('Im a tag!');\n  });\n\n  it('prioritizes slot over test prop', () => {\n    const wrapper = shallowMount(TTag, {\n      props: {\n        text: 'Im a tag!',\n      },\n      slots: {\n        default: 'default slot',\n      },\n    });\n\n    expect(wrapper.vm.$el.innerHTML).toBe('default slot');\n  });\n\n  it('adds the attributes', () => {\n    const wrapper = shallowMount(TTag, {\n      slots: {\n        default: 'default slot',\n      },\n      attrs: {\n        id: 'my-id',\n      },\n    });\n\n    expect(wrapper.html()).toBe('<div id=\"my-id\">default slot</div>');\n  });\n\n  it('adds the attributes from the configuration', () => {\n    const wrapper = shallowMount(TTag, {\n      global: {\n        provide: {\n          configuration: {\n            TTag: {\n              'custom-attribute': 'Hello World!',\n            },\n          },\n        },\n      },\n    });\n\n    expect(wrapper.html()).toBe('<div custom-attribute=\"Hello World!\"></div>');\n  });\n\n  it('used the props from global configuration', () => {\n    const wrapper = shallowMount(TTag, {\n      global: {\n        provide: {\n          configuration: {\n            TTag: {\n              tagName: 'table',\n              text: 'Copyright @alfonsobires',\n            },\n          },\n        },\n      },\n    });\n\n    expect(wrapper.vm.$el.tagName).toBe('TABLE');\n    expect(wrapper.vm.$el.innerHTML).toBe('Copyright @alfonsobires');\n  });\n});\n"
  },
  {
    "path": "src/__tests/components/TTextarea.integration.spec.ts",
    "content": "/* eslint-disable @typescript-eslint/no-non-null-assertion */\nimport { render, fireEvent } from '@testing-library/vue';\nimport TTextarea from '@/components/TTextarea.vue';\n\ndescribe('TTextarea.vue', () => {\n  it('handles the v-model', async () => {\n    const { container, getByDisplayValue } = render(TTextarea);\n\n    const input = container.querySelector('textarea')!;\n\n    await fireEvent.update(input!, 'Alfonso');\n\n    getByDisplayValue('Alfonso');\n  });\n\n  it('contains the class + classes + fixedClasses', async () => {\n    const { container } = render(TTextarea, {\n      props: {\n        fixedClasses: 'text-red-500',\n        classes: 'border-red-500',\n        class: 'font-semibold',\n      },\n    });\n\n    const input = container.querySelector('.text-red-500.border-red-500.font-semibold');\n    expect(input).not.toBeNull();\n  });\n\n  it('adds the html attributes', async () => {\n    const { getByPlaceholderText, getByRole, getByTitle } = render(TTextarea, {\n      props: {\n        placeholder: 'Write something',\n        role: 'text-field',\n        title: 'my title',\n      },\n    });\n\n    getByPlaceholderText('Write something');\n\n    getByRole('text-field');\n\n    getByTitle('my title');\n  });\n\n  it('adds the classes on the variant', async () => {\n    const { container } = render(TTextarea, {\n      props: {\n        variants: {\n          error: {\n            classes: 'text-red-500',\n          },\n        },\n        variant: 'error',\n        classes: 'text-blue-500',\n      },\n    });\n\n    let input = container.querySelector('.text-red-500');\n    expect(input).not.toBeNull();\n\n    input = container.querySelector('.text-blue-500');\n    expect(input).toBeNull();\n  });\n\n  it('keeps the fixedClasses when using a variant', async () => {\n    const { container } = render(TTextarea, {\n      props: {\n        variants: {\n          error: {\n            classes: 'text-red-500',\n          },\n        },\n        variant: 'error',\n        fixedClasses: 'text-blue-500',\n      },\n    });\n\n    let input = container.querySelector('.text-red-500');\n    expect(input).not.toBeNull();\n\n    input = container.querySelector('.text-blue-500');\n    expect(input).not.toBeNull();\n  });\n\n  it('overrides the fixedClasses when using a variant', async () => {\n    const { container } = render(TTextarea, {\n      props: {\n        variants: {\n          error: {\n            fixedClasses: 'text-red-500',\n          },\n        },\n        variant: 'error',\n        fixedClasses: 'text-blue-500',\n      },\n    });\n\n    let input = container.querySelector('.text-red-500');\n    expect(input).not.toBeNull();\n\n    input = container.querySelector('.text-blue-500');\n    expect(input).toBeNull();\n  });\n});\n"
  },
  {
    "path": "src/__tests/components/TTextarea.spec.ts",
    "content": "/* eslint-disable @typescript-eslint/no-non-null-assertion */\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport { shallowMount } from '@vue/test-utils';\nimport { TTextareaConfig } from '@variantjs/core';\nimport TTextarea from '@/components/TTextarea.vue';\n\ndescribe('TTextarea.vue', () => {\n  it('renders the textarea', () => {\n    const wrapper = shallowMount(TTextarea);\n    expect(wrapper.get('textarea')).toBeTruthy();\n  });\n\n  it('renders the textarea with a default set of classes', () => {\n    const wrapper = shallowMount(TTextarea);\n\n    expect(wrapper.html()).toBe(`<textarea class=\"${TTextareaConfig.classes}\"></textarea>`);\n  });\n\n  it('adds the value attribute', () => {\n    const wrapper = shallowMount(TTextarea,\n      {\n        global: {\n          provide: {\n            configuration: {\n              TInput: {\n                classes: undefined,\n              },\n            },\n          },\n        },\n        attrs: {\n          value: 'foo bar',\n        },\n      });\n\n    expect(wrapper.vm.$el.value).toBe('foo bar');\n  });\n\n  it('renders the textarea without attributes if no default theme', () => {\n    const wrapper = shallowMount(TTextarea, {\n      global: {\n        provide: {\n          configuration: {\n            TTextarea: {\n              classes: undefined,\n            },\n          },\n        },\n      },\n    });\n\n    expect(wrapper.html()).toBe('<textarea></textarea>');\n  });\n\n  it('set the props.value into the textarea value', () => {\n    const value = 'textarea value';\n    const wrapper = shallowMount(TTextarea, {\n      props: { modelValue: value, classes: undefined },\n    });\n\n    expect(wrapper.vm.$el.value).toBe(value);\n  });\n\n  it('doesnt add the modelValue as attribute', () => {\n    const value = 'textarea value';\n    const wrapper = shallowMount(TTextarea, {\n      props: { modelValue: value },\n    });\n\n    expect(wrapper.vm.$el.attributes.modelValue).toBeUndefined();\n  });\n\n  it('disables the textarea', async () => {\n    const wrapper = shallowMount(TTextarea, {\n      props: { disabled: false },\n    });\n    expect(wrapper.vm.$el.disabled).toBe(false);\n\n    await wrapper.setProps({ disabled: true });\n\n    expect(wrapper.vm.$el.disabled).toBe(true);\n  });\n\n  it('accepts misc textarea attributes', async () => {\n    const wrapper = shallowMount(TTextarea);\n\n    const values = {\n      id: {\n        default: '',\n        new: 'new-id',\n      },\n      rows: {\n        default: 2,\n        new: 4,\n      },\n      cols: {\n        default: 20,\n        new: 4,\n      },\n      autocomplete: {\n        default: '',\n        new: 'on',\n      },\n      autofocus: {\n        default: false,\n        new: true,\n      },\n      disabled: {\n        default: false,\n        new: true,\n      },\n      maxlength: {\n        keyName: 'maxLength',\n        default: 0,\n        new: 12,\n      },\n      minlength: {\n        keyName: 'minLength',\n        default: 0,\n        new: 2,\n      },\n      name: {\n        default: '',\n        new: 'new-name',\n      },\n      placeholder: {\n        default: '',\n        new: 'new placeholder',\n      },\n      readonly: {\n        keyName: 'readOnly',\n        default: false,\n        new: true,\n      },\n      required: {\n        default: false,\n        new: true,\n      },\n      value: {\n        default: '',\n        new: 'my value',\n      },\n    };\n\n    const newProps: any = {};\n    // Check for the default values\n    Object.keys(values).forEach((key) => {\n      const elementValue = (values as any)[key];\n      expect(wrapper.vm.$el[elementValue.keyName || key]).toBe(elementValue.default);\n\n      newProps[key as any] = elementValue.new;\n    });\n\n    await wrapper.setProps(newProps);\n\n    // Check for the new values\n    Object.keys(values).forEach((key) => {\n      const elementValue = (values as any)[key];\n      expect(wrapper.vm.$el[elementValue.keyName || key]).toBe(elementValue.new);\n    });\n  });\n\n  it('set the model value', () => {\n    const modelValue = 'original value';\n\n    const wrapper = shallowMount(TTextarea, {\n      props: {\n        modelValue,\n      },\n    });\n\n    expect(wrapper.vm.$el.value).toBe(modelValue);\n  });\n\n  it('emits an update event with the textarea value', () => {\n    const modelValue = 'original value';\n\n    const wrapper = shallowMount(TTextarea, {\n      props: {\n        modelValue,\n      },\n    });\n\n    const textareaValue = 'new value';\n\n    wrapper.setValue(textareaValue);\n\n    expect(wrapper.emitted('update:modelValue')).toBeTruthy();\n\n    // assert event count\n    expect(wrapper.emitted('update:modelValue')?.length).toBe(1);\n\n    // assert event payload\n    expect(wrapper.emitted('update:modelValue')![0]).toEqual([textareaValue]);\n  });\n\n  it('emits native textarea events', () => {\n    const onChange = jest.fn();\n    const onBlur = jest.fn();\n    const onFocus = jest.fn();\n    const onKeyup = jest.fn();\n    const onInput = jest.fn();\n\n    const wrapper = shallowMount(TTextarea, {\n      attrs: {\n        onChange,\n        onBlur,\n        onFocus,\n        onKeyup,\n        onInput,\n      },\n    });\n\n    const textarea = wrapper.vm.$el;\n\n    textarea.dispatchEvent(new Event('change'));\n    expect(onChange).toHaveBeenCalled();\n\n    textarea.dispatchEvent(new FocusEvent('focus'));\n    expect(onFocus).toHaveBeenCalled();\n\n    textarea.dispatchEvent(new FocusEvent('blur'));\n    expect(onBlur).toHaveBeenCalled();\n\n    textarea.dispatchEvent(new InputEvent('input'));\n    expect(onInput).toHaveBeenCalled();\n\n    textarea.dispatchEvent(new KeyboardEvent('keyup', { key: 'a' }));\n    expect(onKeyup).toHaveBeenCalled();\n  });\n\n  it('has native textarea methods', () => {\n    const wrapper = shallowMount(TTextarea);\n\n    const textarea = wrapper.vm.$el;\n\n    expect(typeof textarea.click).toBe('function');\n    expect(typeof textarea.select).toBe('function');\n    expect(typeof textarea.setSelectionRange).toBe('function');\n    expect(typeof textarea.setRangeText).toBe('function');\n  });\n\n  it('triggers custom events', async () => {\n    const onCustom = jest.fn();\n\n    const wrapper = shallowMount(TTextarea, {\n      attrs: {\n        onCustom,\n      },\n    });\n    const textarea = wrapper.vm.$el as HTMLTextAreaElement;\n\n    const evt = new CustomEvent('custom', { detail: 'my-custom-event' });\n    textarea.dispatchEvent(evt);\n\n    expect(onCustom).toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "src/__tests/components/TToggle.spec.ts",
    "content": "import { shallowMount } from '@vue/test-utils';\nimport TToggle from '../../components/TToggle.vue';\n\ndescribe('TToggle.vue', () => {\n  it('renders the toggle component', () => {\n    const wrapper = shallowMount(TToggle);\n    expect(wrapper.get('button')).toBeTruthy();\n  });\n\n  it('assigns the uncheckedValue to the localValue', () => {\n    const wrapper = shallowMount(TToggle, {\n      props: {\n        value: 'checked',\n        uncheckedValue: 'unchecked',\n      },\n    });\n\n    expect(wrapper.vm.localValue).toBe('unchecked');\n  });\n\n  it('assigns the checked to the localValue if has a checked prop', () => {\n    const wrapper = shallowMount(TToggle, {\n      props: {\n        value: 'checked',\n        uncheckedValue: 'unchecked',\n        checked: true,\n      },\n    });\n\n    expect(wrapper.vm.localValue).toBe('checked');\n  });\n\n  it('assigns the model value to localValue ', () => {\n    const wrapper = shallowMount(TToggle, {\n      props: {\n        value: 'checked',\n        uncheckedValue: 'unchecked',\n        checked: true,\n        modelValue: 'other',\n      },\n    });\n\n    expect(wrapper.vm.localValue).toBe('other');\n  });\n\n  it('syncs the modelValue', async () => {\n    const wrapper = shallowMount(TToggle, {\n      props: {\n        modelValue: true,\n      },\n    });\n\n    expect(wrapper.vm.localValue).toBe(true);\n\n    await wrapper.setProps({\n      modelValue: false,\n    });\n\n    expect(wrapper.vm.localValue).toBe(false);\n  });\n\n  it('syncs the checked prop', async () => {\n    const wrapper = shallowMount(TToggle, {\n      props: {\n        checked: false,\n        value: 'checked',\n        uncheckedValue: 'unchecked',\n      },\n    });\n\n    expect(wrapper.vm.localValue).toBe('unchecked');\n\n    await wrapper.setProps({\n      checked: true,\n    });\n\n    expect(wrapper.vm.localValue).toBe('checked');\n  });\n\n  it('syncs the checked prop', async () => {\n    const wrapper = shallowMount(TToggle, {\n      props: {\n        checked: false,\n        value: 'checked',\n        uncheckedValue: 'unchecked',\n      },\n    });\n\n    expect(wrapper.vm.localValue).toBe('unchecked');\n\n    await wrapper.setProps({\n      checked: true,\n    });\n\n    expect(wrapper.vm.localValue).toBe('checked');\n  });\n\n  it('adds the name property to the hidden input', () => {\n    const wrapper = shallowMount(TToggle, {\n      props: {\n        name: 'my-toggle',\n      },\n    });\n\n    expect(wrapper.find('input').attributes('name')).toBe('my-toggle');\n  });\n\n  it('assigns the value to the hidden input', async () => {\n    const wrapper = shallowMount(TToggle, {\n      props: {\n        value: 'checked',\n        uncheckedValue: 'unchecked',\n      },\n    });\n\n    expect(wrapper.find('input').attributes('value')).toBe('unchecked');\n\n    wrapper.vm.toggle();\n\n    await wrapper.vm.$nextTick();\n\n    expect(wrapper.find('input').attributes('value')).toBe('checked');\n  });\n\n  it('toggle the value when multiple', async () => {\n    const wrapper = shallowMount(TToggle, {\n      props: {\n        modelValue: ['a', 'b'],\n        value: 'c',\n      },\n    });\n\n    wrapper.vm.toggle();\n\n    await wrapper.vm.$nextTick();\n\n    expect(wrapper.vm.localValue).toEqual(['a', 'b', 'c']);\n\n    wrapper.vm.toggle();\n\n    await wrapper.vm.$nextTick();\n\n    expect(wrapper.vm.localValue).toEqual(['a', 'b']);\n  });\n\n  it('hides the hidden input when its an array and value is not selected', async () => {\n    const wrapper = shallowMount(TToggle, {\n      props: {\n        modelValue: ['a', 'c'],\n        value: 'b',\n      },\n    });\n\n    // Not checked since its not part of the modelValue\n    expect(wrapper.find('input').exists()).toBe(false);\n\n    wrapper.vm.toggle();\n\n    await wrapper.vm.$nextTick();\n\n    expect(wrapper.vm.localValue).toEqual(['a', 'c', 'b']);\n    expect(wrapper.find('input').attributes('value')).toBe('b');\n  });\n\n  it('returns the classes for the wrapper and the button according to the state', async () => {\n    const wrapper = shallowMount(TToggle, {\n      props: {\n        fixedClasses: undefined,\n        classes: {\n          wrapper: 'wrapper',\n          button: 'button',\n          wrapperChecked: 'wrapper-checked',\n          buttonChecked: 'button-checked',\n          wrapperDisabled: 'wrapper-disabled',\n          wrapperCheckedDisabled: 'wrapper-checked-disabled',\n        },\n      },\n    });\n\n    expect(wrapper.vm.classes).toEqual({\n      wrapper: 'wrapper',\n      button: 'button',\n    });\n\n    await wrapper.setProps({\n      checked: true,\n    });\n\n    expect(wrapper.vm.classes).toEqual({\n      wrapper: 'wrapper-checked',\n      button: 'button-checked',\n    });\n\n    await wrapper.setProps({\n      checked: true,\n      disabled: true,\n    });\n\n    expect(wrapper.vm.classes).toEqual({\n      wrapper: 'wrapper-checked-disabled',\n      button: 'button-checked',\n    });\n\n    await wrapper.setProps({\n      checked: false,\n      disabled: true,\n    });\n\n    expect(wrapper.vm.classes).toEqual({\n      wrapper: 'wrapper-disabled',\n      button: 'button',\n    });\n  });\n});\n"
  },
  {
    "path": "src/__tests/components/icons/CustomIcon.spec.ts",
    "content": "import { mount } from '@vue/test-utils';\nimport CustomIcon from '@/icons/CustomIcon.vue';\nimport CloseIcon from '@/icons/CloseIcon.vue';\n\ndescribe('CustomIcon.vue', () => {\n  it('accepts a SVG string as a closeIcon', async () => {\n    const icon = `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n    <path fill-rule=\"evenodd\" d=\"M12.707\" clip-rule=\"evenodd\"></path>\n  </svg>`;\n    const wrapper = mount(CustomIcon, {\n      props: {\n        icon,\n      },\n    });\n\n    expect(wrapper.vm.$el.innerHTML).toContain('<path fill-rule=\"evenodd\" d=\"M12.707\" clip-rule=\"evenodd\"');\n  });\n\n  it('strips malicious attributes', async () => {\n    const icon = `<svg onload=\"alert(document.cookie)\"  xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\">\n    <path fill-rule=\"evenodd\" d=\"M12.707\" clip-rule=\"evenodd\"></path>\n  </svg>`;\n    const wrapper = mount(CustomIcon, {\n      props: {\n        icon,\n      },\n    });\n\n    expect(wrapper.vm.$el.innerHTML).not.toContain('document.cookie');\n  });\n\n  it('accepts another vue component as a custom icon', async () => {\n    // Supress Vue received a Component which was made a reactive object.This can lead to unnecessary performance overhead, and should be avoided by marking the component with `markRaw` or using `shallowRef` instead of `ref\n    // @TODO consider an alternative to this\n    jest.spyOn(console, 'warn').mockImplementation(() => {});\n\n    const wrapper = mount(CustomIcon, {\n      props: {\n        icon: CloseIcon,\n      },\n    });\n\n    expect(wrapper.vm.$el.innerHTML).toContain('M6 18L18 6M6 6l12 12');\n  });\n});\n"
  },
  {
    "path": "src/__tests/components/misc/TextPlaceholder.spec.ts",
    "content": "import { shallowMount } from '@vue/test-utils';\nimport TextPlaceholder from '../../../components/misc/TextPlaceholder.vue';\n\ndescribe('TextPlaceholder', () => {\n  it('renders a blank space if no TextPlaceholder is set', () => {\n    const wrapper = shallowMount(TextPlaceholder);\n\n    expect(wrapper.vm.$el.innerHTML).toEqual('&nbsp;');\n  });\n\n  it('uses the text inside the default prop', () => {\n    const wrapper = shallowMount(TextPlaceholder, {\n      slots: {\n        default: 'Select an option',\n      },\n    });\n\n    expect(wrapper.vm.$el.innerHTML).toEqual('Select an option');\n  });\n\n  it('uses `placeholder` as the property from the `classesList` by default', () => {\n    const configuration = {\n      classesList: { placeholder: 'text-red-500' },\n    };\n\n    const wrapper = shallowMount(TextPlaceholder, {\n      global: {\n        provide: {\n          configuration,\n        },\n      },\n    });\n\n    expect(wrapper.vm.$el.className).toEqual('text-red-500');\n  });\n\n  it('accepts a different property for the `classesList` by object', () => {\n    const configuration = {\n      classesList: { buttonPlaceholder: 'text-red-500' },\n    };\n    const wrapper = shallowMount(TextPlaceholder, {\n      global: {\n        provide: {\n          configuration,\n        },\n      },\n      props: {\n        classProperty: 'buttonPlaceholder',\n      },\n    });\n\n    expect(wrapper.vm.$el.className).toEqual('text-red-500');\n  });\n\n  it('uses the prop placeholder if set', () => {\n    const wrapper = shallowMount(TextPlaceholder, {\n      props: {\n        placeholder: 'Select an option',\n      },\n    });\n\n    expect(wrapper.vm.$el.innerHTML).toEqual('Select an option');\n  });\n\n  it('prioritized the slot over the placeholder attribute', () => {\n    const wrapper = shallowMount(TextPlaceholder, {\n      props: {\n        placeholder: 'Something else',\n      },\n      slots: {\n        default: 'Select an option',\n      },\n    });\n\n    expect(wrapper.vm.$el.innerHTML).toEqual('Select an option');\n  });\n});\n"
  },
  {
    "path": "src/__tests/components/misc/Transitionable.spec.ts",
    "content": "import Transitionable from '../../../components/misc/Transitionable.vue';\n\ndescribe('Transitionable', () => {\n  it('defaults the classes list to an empty object', () => {\n    expect(Transitionable.props.classesList.default()).toEqual({});\n  });\n});\n"
  },
  {
    "path": "src/__tests/index.spec.ts",
    "content": "import * as library from '../index';\n\ndescribe('main file', () => {\n  it('provides all the needed data', () => {\n    expect(Object.keys(library)).toEqual([\n      'TInput',\n      'TButton',\n      'TTextarea',\n      'TSelect',\n      'TCheckbox',\n      'TRadio',\n      'TInputGroup',\n      'TRichSelect',\n      'TTag',\n      'TCard',\n      'TDropdown',\n      'TAlert',\n      'TModal',\n      'TDialog',\n      'TToggle',\n      'variantJS',\n      'LoadingIcon',\n      'Emitter',\n      'getVariantProps',\n      'getVariantPropsWithClassesList',\n      'sameWidthModifier',\n      'svgToVueComponent',\n      'useActivableOption',\n      'useConfiguration',\n      'useConfigurationWithClassesList',\n      'useFetchsOptions',\n      'useInjectsClassesList',\n      'useInjectsClassesListClass',\n      'useInjectsConfiguration',\n      'useMulipleableVModel',\n      'useMultioptions',\n      'useSelectableOption',\n      'useVModel',\n    ]);\n  });\n\n  describe('callable utils', () => {\n    it('can create an instance of emitter', () => {\n      const emitter = new library.Emitter();\n\n      expect(emitter).toBeInstanceOf(library.Emitter);\n    });\n\n    it('have functions', () => {\n      expect(typeof library.getVariantProps).toBe('function');\n      expect(typeof library.getVariantPropsWithClassesList).toBe('function');\n      expect(typeof library.sameWidthModifier).toBe('object');\n      expect(typeof library.svgToVueComponent).toBe('function');\n    });\n  });\n});\n"
  },
  {
    "path": "src/__tests/plugin.spec.ts",
    "content": "/* eslint-disable vue/one-component-per-file */\nimport { createApp } from 'vue';\nimport { variantJS } from '..';\nimport { VariantJSConfiguration } from '../types';\nimport { Emitter } from '../utils/emitter';\n\ndescribe('plugin installer', () => {\n  it('provides the configuration', () => {\n    const app = createApp({});\n\n    const configuration: VariantJSConfiguration = {\n      TInput: {\n        placeholder: 'Whatever',\n      },\n    };\n\n    app.use(variantJS, configuration);\n\n    const component = app.component('ExampleComponent', {});\n\n    // eslint-disable-next-line no-underscore-dangle\n    expect(component._context.provides.configuration).toEqual(configuration);\n  });\n\n  it('handles an empty configuration', () => {\n    const app = createApp({});\n\n    app.use(variantJS);\n\n    const component = app.component('ExampleComponent', {});\n\n    // eslint-disable-next-line no-underscore-dangle\n    expect(component._context.provides.configuration).toEqual({});\n  });\n\n  it('provides an emitter ', () => {\n    const app = createApp({});\n\n    app.use(variantJS);\n\n    // eslint-disable-next-line no-underscore-dangle\n    expect(app._context.provides.emitter).toBeInstanceOf(Emitter);\n  });\n\n  it('adds a $modal util as a global property', () => {\n    const app = createApp({});\n\n    app.use(variantJS);\n\n    expect(typeof app.config.globalProperties.$modal).toBe('object');\n\n    expect(typeof app.config.globalProperties.$modal.show).toBe('function');\n\n    expect(typeof app.config.globalProperties.$modal.hide).toBe('function');\n  });\n\n  it('adds a $dialog util as a global property', () => {\n    const app = createApp({});\n\n    app.use(variantJS);\n\n    expect(typeof app.config.globalProperties.$dialog).toBe('object');\n\n    expect(typeof app.config.globalProperties.$dialog.show).toBe('function');\n\n    expect(typeof app.config.globalProperties.$dialog.hide).toBe('function');\n    expect(typeof app.config.globalProperties.$dialog.alert).toBe('function');\n    expect(typeof app.config.globalProperties.$dialog.prompt).toBe('function');\n    expect(typeof app.config.globalProperties.$dialog.confirm).toBe('function');\n\n    expect(typeof app.config.globalProperties.$alert).toBe('function');\n    expect(typeof app.config.globalProperties.$prompt).toBe('function');\n    expect(typeof app.config.globalProperties.$confirm).toBe('function');\n  });\n\n  it('the alert, prompt and confirm methods are callable', () => {\n    const app = createApp({});\n\n    app.use(variantJS);\n\n    expect(app.config.globalProperties.$confirm('Title')).toBeInstanceOf(Promise);\n    expect(app.config.globalProperties.$alert('Title')).toBeInstanceOf(Promise);\n    expect(app.config.globalProperties.$prompt('Title')).toBeInstanceOf(Promise);\n  });\n});\n"
  },
  {
    "path": "src/__tests/testUtils.ts",
    "content": "/* eslint-disable @typescript-eslint/explicit-module-boundary-types */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { Data } from '@variantjs/core';\n\nexport const scopedParamsAsString = (params: Data) : string => {\n  const keys = Object.keys(params);\n  const result: Data = {};\n  keys.filter((key) => key !== 'key').forEach((key) => {\n    result[key] = typeof params[key];\n  });\n  return JSON.stringify(result);\n};\n\nexport const parseScopedParams = (paramsAsString: string) : Data => JSON.parse(paramsAsString);\n\nexport const getChildComponentNameByRef = (wrapper: any, refName: string): string | undefined => {\n  const component = wrapper.vm.$refs[refName];\n\n  return component?.$?.type.name;\n};\n\nexport const componentHasAttributeWithValue = (component: any, attributeName: string, attributeValue: any): boolean => component.$.attrs[attributeName] === attributeValue;\n\nexport const componentHasAttributeWithInlineHandlerAndParameter = (component: any, attributeName: string, parameterName: any): boolean => {\n  const functionAsString: string = component.$.attrs[attributeName].toString();\n  return functionAsString.includes(parameterName);\n};\n"
  },
  {
    "path": "src/__tests/use/useActivableOption.spec.ts",
    "content": "import { NormalizedOption } from '@variantjs/core';\nimport {\n  ComputedRef, computed, ref, Ref, nextTick,\n} from 'vue';\nimport useActivableOption from '../../use/useActivableOption';\nimport { useSetup } from './useSetup';\n\ndescribe('useActivableOption', () => {\n  const optionsRef = ref<NormalizedOption[]>([\n    { value: 'a', text: 'Option A' },\n    { value: 'b', text: 'Option B' },\n    { value: 'c', text: 'Option C' },\n  ]);\n\n  const options: ComputedRef<NormalizedOption[]> = computed(() => optionsRef.value);\n\n  const localValue: Ref = ref(null);\n\n  beforeEach(() => {\n    localValue.value = null;\n\n    optionsRef.value = [\n      { value: 'a', text: 'Option A' },\n      { value: 'b', text: 'Option B' },\n      { value: 'c', text: 'Option C' },\n    ];\n  });\n\n  it('contains an activeOption ref and initActiveOption, optionIsActive, setActiveOption, setNextOptionActive, setPrevOptionActive methods', () => {\n    useSetup(() => {\n      const {\n        activeOption, initActiveOption, optionIsActive, setActiveOption, setNextOptionActive, setPrevOptionActive,\n      } = useActivableOption(\n        options,\n        localValue,\n      );\n\n      expect(typeof activeOption).toBe('object');\n      expect(typeof initActiveOption).toBe('function');\n      expect(typeof optionIsActive).toBe('function');\n      expect(typeof setActiveOption).toBe('function');\n      expect(typeof setNextOptionActive).toBe('function');\n      expect(typeof setPrevOptionActive).toBe('function');\n    });\n  });\n\n  it('sets the active option', () => {\n    useSetup(() => {\n      const {\n        activeOption, setActiveOption,\n      } = useActivableOption(\n        computed(() => [\n          { value: 'a', text: 'Option A' },\n          { value: 'b', text: 'Option B' },\n          { value: 'c', text: 'Option C' },\n        ]),\n        localValue,\n      );\n\n      setActiveOption({ ...options.value[1] });\n\n      expect(activeOption.value).toEqual({ ...options.value[1] });\n    });\n  });\n\n  it('sets the first not-disabled option when as active if the selected option is disabled', () => {\n    useSetup(() => {\n      const {\n        activeOption, initActiveOption,\n      } = useActivableOption(\n        computed(() => [\n          { value: 'a', text: 'Option A', disabled: true },\n          { value: 'b', text: 'Option B', disabled: true },\n          { value: 'c', text: 'Option C' },\n        ]),\n        ref('b'),\n      );\n\n      initActiveOption();\n\n      expect(activeOption.value?.value).toBe('c');\n    });\n  });\n\n  it('sets null if didnt find any enabled option', () => {\n    useSetup(() => {\n      const {\n        activeOption, initActiveOption,\n      } = useActivableOption(\n        computed(() => [\n          { value: 'a', text: 'Option A', disabled: true },\n          { value: 'b', text: 'Option B', disabled: true },\n        ]),\n        ref('b'),\n      );\n\n      initActiveOption();\n\n      expect(activeOption.value).toBe(null);\n    });\n  });\n\n  describe('options change', () => {\n    it('sets the active option to the first new option when initially set', () => {\n      optionsRef.value = [];\n\n      useSetup(async () => {\n        const {\n          activeOption,\n        } = useActivableOption(\n          options,\n          localValue,\n        );\n\n        optionsRef.value = [{ value: 'foo', text: 'Bar' }];\n\n        await nextTick();\n\n        expect(activeOption.value!.value).toEqual('d');\n      });\n    });\n\n    it('doesnt set an active option if no options', () => {\n      optionsRef.value = [];\n\n      useSetup(async () => {\n        const {\n          activeOption,\n        } = useActivableOption(\n          options,\n          localValue,\n        );\n\n        optionsRef.value = [];\n\n        await nextTick();\n\n        expect(activeOption.value).toBe(null);\n      });\n    });\n\n    it('sets the active option to the first new option ', () => {\n      useSetup(async () => {\n        const {\n          activeOption,\n        } = useActivableOption(\n          options,\n          localValue,\n        );\n\n        expect(activeOption.value!.value).toEqual('a');\n\n        optionsRef.value.push({ value: 'd', text: 'Option D' });\n\n        await nextTick();\n\n        expect(activeOption.value!.value).toEqual('d');\n      });\n    });\n  });\n\n  describe('optionIsActive', () => {\n    it('deletermines if an option optionIsActive when activeOption is null', () => {\n      useSetup(() => {\n        const {\n          activeOption, optionIsActive,\n        } = useActivableOption(\n          options,\n          localValue,\n        );\n\n        activeOption.value = null;\n\n        expect(optionIsActive({ ...options.value[1] })).toBe(false);\n      });\n    });\n\n    it('deletermines if an option optionIsActive when activeOption is equal to option', () => {\n      useSetup(() => {\n        const {\n          activeOption, optionIsActive,\n        } = useActivableOption(\n          options,\n          localValue,\n        );\n\n        activeOption.value = { ...options.value[1] };\n\n        expect(optionIsActive({ ...options.value[1] })).toBe(true);\n      });\n    });\n\n    it('deletermines if an option optionIsActive when activeOption is not equal to option', () => {\n      useSetup(() => {\n        const {\n          activeOption, optionIsActive,\n        } = useActivableOption(\n          options,\n          localValue,\n        );\n\n        activeOption.value = { ...options.value[0] };\n\n        expect(optionIsActive({ ...options.value[1] })).toBe(false);\n      });\n    });\n  });\n\n  it('returns the first option if no one is selected', () => {\n    useSetup(() => {\n      const {\n        activeOption,\n      } = useActivableOption(\n        options,\n        localValue,\n      );\n\n      expect(activeOption.value).toEqual(options.value[0]);\n    });\n  });\n\n  it('return null if the options list is empty', () => {\n    useSetup(() => {\n      const {\n        activeOption,\n      } = useActivableOption(\n        computed(() => []),\n        localValue,\n      );\n\n      expect(activeOption.value).toBeNull();\n    });\n  });\n\n  it('return the active option', () => {\n    localValue.value = 'b';\n\n    useSetup(() => {\n      const {\n        activeOption,\n\n      } = useActivableOption(\n        options,\n        localValue,\n      );\n\n      expect(activeOption.value).toEqual(options.value[1]);\n    });\n  });\n\n  it('sets the active option with the `setActiveOption` method', () => {\n    useSetup(() => {\n      const {\n        activeOption, setActiveOption,\n      } = useActivableOption(\n        options,\n        localValue,\n      );\n\n      setActiveOption(options.value[1]);\n\n      expect(activeOption.value).toEqual(options.value[1]);\n    });\n  });\n\n  describe('setNextOptionActive', () => {\n    it('sets the next index as active', () => {\n      useSetup(() => {\n        const {\n          activeOption, setNextOptionActive,\n        } = useActivableOption(\n          options,\n          localValue,\n        );\n\n        setNextOptionActive();\n\n        expect(activeOption.value).toEqual(options.value[1]);\n      });\n    });\n\n    it('sets the next index that is not disabled as active', () => {\n      useSetup(() => {\n        const {\n          activeOption, setNextOptionActive,\n        } = useActivableOption(\n          computed(() => [\n            { value: 'a', text: 'Option A' },\n            { value: 'b', text: 'Option B', disabled: true },\n            { value: 'c', text: 'Option C' },\n          ]),\n          localValue,\n        );\n\n        setNextOptionActive();\n\n        expect(activeOption.value).toEqual(options.value[2]);\n      });\n    });\n\n    it('keeps the current option if is the last one', () => {\n      useSetup(() => {\n        const {\n          activeOption, setNextOptionActive, setActiveOption,\n        } = useActivableOption(\n          options,\n          localValue,\n        );\n\n        setActiveOption(options.value[2]);\n\n        setNextOptionActive();\n\n        expect(activeOption.value).toEqual(options.value[2]);\n      });\n    });\n\n    it('considers the option index as zero when no active option selected', () => {\n      useSetup(() => {\n        const {\n          activeOption, setNextOptionActive,\n        } = useActivableOption(\n          options,\n          localValue,\n        );\n\n        activeOption.value = null;\n\n        setNextOptionActive();\n\n        expect(activeOption.value).toEqual(options.value[1]);\n      });\n    });\n\n    it('considers the option index as zero when no the active option is not found', () => {\n      useSetup(() => {\n        const {\n          activeOption, setNextOptionActive,\n        } = useActivableOption(\n          options,\n          localValue,\n        );\n\n        activeOption.value = { value: 'other', text: 'Other' };\n\n        setNextOptionActive();\n\n        expect(activeOption.value).toEqual(options.value[1]);\n      });\n    });\n  });\n\n  describe('setPrevOptionActive', () => {\n    it('sets the prev index as active', () => {\n      useSetup(() => {\n        const {\n          activeOption, setPrevOptionActive, setActiveOption,\n        } = useActivableOption(\n          options,\n          localValue,\n        );\n\n        setActiveOption(options.value[1]);\n\n        setPrevOptionActive();\n\n        expect(activeOption.value).toEqual(options.value[0]);\n      });\n    });\n\n    it('sets the prex index that is not disabled as active', () => {\n      useSetup(() => {\n        const {\n          activeOption, setPrevOptionActive, setActiveOption,\n        } = useActivableOption(\n          computed(() => [\n            { value: 'a', text: 'Option A' },\n            { value: 'b', text: 'Option B', disabled: true },\n            { value: 'c', text: 'Option C' },\n          ]),\n          localValue,\n        );\n\n        setActiveOption(options.value[2]);\n\n        setPrevOptionActive();\n\n        expect(activeOption.value).toEqual(options.value[0]);\n      });\n    });\n\n    it('keeps the first one selected if its the current option', () => {\n      useSetup(() => {\n        const {\n          activeOption, setPrevOptionActive,\n        } = useActivableOption(\n          options,\n          localValue,\n        );\n\n        setPrevOptionActive();\n\n        expect(activeOption.value).toEqual(options.value[0]);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "src/__tests/use/useConfiguration.spec.ts",
    "content": "import { shallowMount } from '@vue/test-utils';\nimport useConfiguration from '../../use/useConfiguration';\nimport { useSetup } from './useSetup';\nimport TTag from '@/components/TTag.vue';\n\ndescribe('useConfiguration', () => {\n  describe('configuration', () => {\n    it('should keep the default configuration', () => {\n      useSetup(() => {\n        const { configuration } = useConfiguration({\n          attrib: 'value',\n          width: '10px',\n        });\n        expect(configuration).toEqual({\n          attrib: 'value',\n          width: '10px',\n        });\n      });\n    });\n\n    it('should merge the classes from the configuration', () => {\n      useSetup(() => {\n        const { configuration } = useConfiguration({\n          classes: 'text-red-500',\n          fixedClasses: 'border-2',\n        });\n        expect(configuration).toEqual({\n          class: 'text-red-500 border-2',\n        });\n      });\n    });\n\n    it('should merge the classes from the configuration variant', () => {\n      useSetup(() => {\n        const { configuration } = useConfiguration({\n          classes: 'text-blue-500',\n          fixedClasses: 'border',\n          variants: {\n            error: {\n              classes: 'text-red-500',\n              fixedClasses: 'border-2',\n            },\n          },\n          variant: 'error',\n        });\n        expect(configuration).toEqual({\n          class: 'text-red-500 border-2',\n        });\n      });\n    });\n\n    it('should merge the global configuration', () => {\n      const globalConfiguration = {\n        TInput: {\n          placeholder: 'Hello world',\n        },\n      };\n      useSetup(() => {\n        const { configuration } = useConfiguration({\n          maxlength: '2',\n        });\n\n        expect(configuration).toEqual({\n          maxlength: '2',\n          placeholder: 'Hello world',\n        });\n      }, globalConfiguration);\n    });\n\n    it('should use the default values from the props if not overriden', () => {\n      const globalConfiguration = {};\n      const attrs = {};\n      const props = {\n        placeholder: {\n          type: String,\n          default: 'Hello world',\n        },\n      };\n      useSetup(() => {\n        const { configuration } = useConfiguration({\n          maxlength: '2',\n        });\n\n        expect(configuration).toEqual({\n          maxlength: '2',\n          placeholder: 'Hello world',\n        });\n      }, globalConfiguration, attrs, props);\n    });\n  });\n\n  describe('attributes', () => {\n    it('contains the configuration the attributes', () => {\n      useSetup(() => {\n        const props = {\n          placeholder: 'Hello World',\n        };\n\n        const { attributes } = useConfiguration(props);\n\n        expect(attributes).toEqual({\n          placeholder: 'Hello World',\n        });\n      }, {}, {});\n    });\n\n    it('contains the class + classes + fixedClasses', () => {\n      useSetup(() => {\n        const props = {\n          fixedClasses: 'text-red-500',\n          classes: 'border-red-500',\n          class: 'font-semibold',\n        };\n\n        const { attributes } = useConfiguration(props);\n\n        expect(attributes).toEqual({\n          class: 'font-semibold border-red-500 text-red-500',\n        });\n      }, {}, {}, ['fixedClasses', 'classes']);\n    });\n\n    it('adds the configurations attributes', () => {\n      useSetup(() => {\n        const props = {\n          type: 'button',\n          'data-id': 'something',\n        };\n\n        const { attributes } = useConfiguration(props);\n\n        expect(attributes).toEqual({\n          type: 'button',\n          'data-id': 'something',\n        });\n      });\n    });\n\n    it('doesnt add the configurations attributes defined as a props', () => {\n      useSetup(() => {\n        const props = {\n          type: 'button',\n          'data-id': 'something',\n        };\n        const { attributes } = useConfiguration(props);\n\n        expect(attributes).toEqual({\n          'data-id': 'something',\n        });\n      }, {}, {}, ['type']);\n    });\n\n    it('updates the attributes when the configuration changes', async () => {\n      const configuration = {\n        TInput: {\n          'data-id': 'something',\n        },\n      };\n\n      const wrapper = shallowMount(TTag, {\n        props: {\n          tagName: 'div',\n        },\n        global: {\n          provide: {\n            configuration,\n          },\n        },\n      });\n\n      wrapper.vm.$.setupState.configuration['data-id'] = 'something-else';\n\n      await wrapper.vm.$nextTick();\n\n      expect(wrapper.vm.$.setupState.attributes).toEqual({\n        'data-id': 'something-else',\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "src/__tests/use/useConfigurationWithClassesList.spec.ts",
    "content": "import useConfigurationWithClassesList from '../../use/useConfigurationWithClassesList';\nimport { useSetup } from './useSetup';\n\ndescribe('useConfigurationWithClassesList', () => {\n  describe('configuration', () => {\n    it('should keep the default configuration', () => {\n      useSetup(() => {\n        const { configuration } = useConfigurationWithClassesList({\n          attrib: 'value',\n          width: '10px',\n          classes: {\n            wrapper: 'border',\n            body: 'text-base',\n          },\n        }, ['wrapper', 'body']);\n\n        expect(configuration).toEqual({\n          attrib: 'value',\n          width: '10px',\n          classesList: {\n            wrapper: 'border',\n            body: 'text-base',\n          },\n        });\n      });\n    });\n\n    it('should merge the classes from the configuration', () => {\n      useSetup(() => {\n        const { configuration } = useConfigurationWithClassesList({\n          classes: {\n            wrapper: 'border',\n            body: 'text-base',\n          },\n          fixedClasses: {\n            wrapper: 'border-gray-200',\n            body: 'p-3',\n          },\n        }, ['wrapper', 'body']);\n        expect(configuration).toEqual({\n          classesList: {\n            wrapper: 'border border-gray-200',\n            body: 'text-base p-3',\n          },\n        });\n      });\n    });\n\n    it('should override the classes from the configuration variant', () => {\n      useSetup(() => {\n        const { configuration } = useConfigurationWithClassesList({\n          classes: {\n            wrapper: 'border',\n            body: 'text-base',\n          },\n          fixedClasses: {\n            wrapper: 'border-gray-200',\n            body: 'p-3',\n          },\n          variants: {\n            error: {\n              classes: {\n                wrapper: 'border-2',\n              },\n            },\n          },\n          variant: 'error',\n        }, ['wrapper', 'body']);\n        expect(configuration).toEqual({\n          classesList: {\n            wrapper: 'border-2 border-gray-200',\n            body: 'text-base p-3',\n          },\n        });\n      });\n    });\n\n    it('should merge the global configuration', () => {\n      const globalConfiguration = {\n        TCard: {\n          placeholder: 'Hello world',\n          classes: {\n            wrapper: 'border',\n            body: 'text-base',\n          },\n        },\n      };\n      useSetup(() => {\n        const { configuration } = useConfigurationWithClassesList({\n          maxlength: '2',\n        }, ['wrapper', 'body']);\n\n        expect(configuration).toEqual({\n          maxlength: '2',\n          placeholder: 'Hello world',\n          classesList: {\n            wrapper: 'border',\n            body: 'text-base',\n          },\n        });\n      }, globalConfiguration, {}, {}, 'TCard');\n    });\n\n    it('should use the default values from the props if not overriden', () => {\n      const globalConfiguration = {};\n      const attrs = {};\n      const props = {\n        body: {\n          type: String,\n          default: 'Hello world',\n        },\n      };\n      useSetup(() => {\n        const { configuration } = useConfigurationWithClassesList({\n          maxlength: '2',\n        }, ['wrapper', 'body']);\n\n        expect(configuration).toEqual({\n          maxlength: '2',\n          body: 'Hello world',\n        });\n      }, globalConfiguration, attrs, props);\n    });\n  });\n\n  describe('attributes', () => {\n    it('contains the configuration the attributes', () => {\n      useSetup(() => {\n        const props = {\n          placeholder: 'Hello World',\n        };\n\n        const { attributes } = useConfigurationWithClassesList(props, []);\n\n        expect(attributes).toEqual({\n          placeholder: 'Hello World',\n        });\n      }, {}, {});\n    });\n\n    it('adds the configurations attributes', () => {\n      useSetup(() => {\n        const props = {\n          type: 'button',\n          'data-id': 'something',\n        };\n\n        const { attributes } = useConfigurationWithClassesList(props, []);\n\n        expect(attributes).toEqual({\n          type: 'button',\n          'data-id': 'something',\n        });\n      });\n    });\n\n    it('doesnt add the configurations attributes defined as a props', () => {\n      useSetup(() => {\n        const props = {\n          type: 'button',\n          'data-id': 'something',\n        };\n        const { attributes } = useConfigurationWithClassesList(props, []);\n\n        expect(attributes).toEqual({\n          'data-id': 'something',\n        });\n      }, {}, {}, ['type']);\n    });\n  });\n});\n"
  },
  {
    "path": "src/__tests/use/useFetchsOptions.spec.ts",
    "content": "/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { nextTick, ref } from 'vue';\nimport { FetchOptionsFn, MinimumInputLengthTextProp, PreFetchOptionsFn } from '../../types';\nimport useFetchsOptions from '../../use/useFetchsOptions';\nimport { useSetup } from './useSetup';\n\ndescribe('useFetchsOptions', () => {\n  const localValue = ref<any>(undefined);\n  const options = ref<string[] | undefined>(['A', 'B']);\n  const textAttribute = ref<string | undefined>(undefined);\n  const valueAttribute = ref<string | undefined>(undefined);\n  const normalize = ref<boolean>(true);\n  const searchQuery = ref<string | undefined>(undefined);\n  const fetchFn = ref<FetchOptionsFn | undefined>(undefined);\n  const prefetchFn = ref<PreFetchOptionsFn | boolean>(false);\n  const fetchDelay = ref<number | undefined>(undefined);\n  const fetchMinimumInputLength = ref<number | undefined>(undefined);\n  const fetchMinimumInputLengthText = ref<MinimumInputLengthTextProp>((minimumInputLength: number): string => `Please enter ${minimumInputLength} or more characters`);\n\n  beforeEach(() => {\n    options.value = ['A', 'B'];\n    textAttribute.value = undefined;\n    valueAttribute.value = undefined;\n    normalize.value = true;\n    searchQuery.value = undefined;\n    fetchFn.value = undefined;\n    fetchDelay.value = undefined;\n    fetchMinimumInputLength.value = undefined;\n    fetchMinimumInputLengthText.value = (minimumInputLength: number): string => `Please enter ${minimumInputLength} or more characters`;\n  });\n\n  describe('no fetch function', () => {\n    it('returns normalized options', () => {\n      useSetup(() => {\n        const { normalizedOptions } = useFetchsOptions(\n          localValue,\n          options,\n          textAttribute,\n          valueAttribute,\n          normalize,\n          searchQuery,\n          fetchFn,\n          prefetchFn,\n          fetchDelay,\n          fetchMinimumInputLength,\n          fetchMinimumInputLengthText,\n        );\n\n        expect(normalizedOptions.value).toEqual([\n          { raw: 'A', text: 'A', value: 'A' },\n          { raw: 'B', text: 'B', value: 'B' },\n        ]);\n      });\n    });\n\n    it('returns empty array of normalized options if options became undefined', () => {\n      useSetup(() => {\n        const { normalizedOptions } = useFetchsOptions(\n          localValue,\n          options,\n          textAttribute,\n          valueAttribute,\n          normalize,\n          searchQuery,\n          fetchFn,\n          prefetchFn,\n          fetchDelay,\n          fetchMinimumInputLength,\n          fetchMinimumInputLengthText,\n        );\n\n        options.value = undefined;\n\n        expect(normalizedOptions.value).toEqual([]);\n      });\n    });\n\n    it('returns flattened options', () => {\n      useSetup(() => {\n        const { flattenedOptions } = useFetchsOptions(\n          localValue,\n          ref([\n            { text: 'A', value: 'A' },\n            {\n              text: 'B', value: 'B', children: ['C'],\n            },\n          ]),\n          textAttribute,\n          valueAttribute,\n          normalize,\n          searchQuery,\n          fetchFn,\n          prefetchFn,\n          fetchDelay,\n          fetchMinimumInputLength,\n          fetchMinimumInputLengthText,\n        );\n\n        expect(flattenedOptions.value).toEqual(\n          [\n            { value: 'A', text: 'A', raw: { text: 'A', value: 'A' } },\n            { value: 'C', text: 'C', raw: 'C' },\n          ],\n        );\n      });\n    });\n\n    it('handles undefined options', () => {\n      useSetup(() => {\n        const { normalizedOptions } = useFetchsOptions(\n          localValue,\n          ref(undefined),\n          textAttribute,\n          valueAttribute,\n          normalize,\n          searchQuery,\n          fetchFn,\n          prefetchFn,\n          fetchDelay,\n          fetchMinimumInputLength,\n          fetchMinimumInputLengthText,\n        );\n\n        expect(normalizedOptions.value).toEqual([]);\n      });\n    });\n\n    it('accepts a custom `textAttribute`', () => {\n      useSetup(() => {\n        const { normalizedOptions } = useFetchsOptions(\n          localValue,\n          ref([\n            { label: 'Letter A', value: 'A' },\n            { label: 'Letter B', value: 'B' },\n          ]),\n          ref('label'),\n          valueAttribute,\n          normalize,\n          searchQuery,\n          fetchFn,\n          prefetchFn,\n          fetchDelay,\n          fetchMinimumInputLength,\n          fetchMinimumInputLengthText,\n        );\n\n        expect(normalizedOptions.value).toEqual([\n          { raw: { label: 'Letter A', value: 'A' }, text: 'Letter A', value: 'A' },\n          { raw: { label: 'Letter B', value: 'B' }, text: 'Letter B', value: 'B' },\n        ]);\n      });\n    });\n\n    it('accepts a custom `valueAttribute`', () => {\n      useSetup(() => {\n        const { normalizedOptions } = useFetchsOptions(\n          localValue,\n          ref([\n            { text: 'A', identifier: 'a' },\n            { text: 'B', identifier: 'b' },\n          ]),\n          textAttribute,\n          ref('identifier'),\n          normalize,\n          searchQuery,\n          fetchFn,\n          prefetchFn,\n          fetchDelay,\n          fetchMinimumInputLength,\n          fetchMinimumInputLengthText,\n        );\n\n        expect(normalizedOptions.value).toEqual([\n          { raw: { text: 'A', identifier: 'a' }, text: 'A', value: 'a' },\n          { raw: { text: 'B', identifier: 'b' }, text: 'B', value: 'b' },\n        ]);\n      });\n    });\n\n    it('doesnt normalize the options if normalize is `false`', () => {\n      useSetup(() => {\n        const { normalizedOptions } = useFetchsOptions(\n          localValue,\n          options,\n          textAttribute,\n          valueAttribute,\n          ref(false),\n          searchQuery,\n          fetchFn,\n          prefetchFn,\n          fetchDelay,\n          fetchMinimumInputLength,\n          fetchMinimumInputLengthText,\n        );\n\n        expect(normalizedOptions.value).toEqual(options.value);\n      });\n    });\n\n    describe('with search query', () => {\n      it('filters by the search query', () => {\n        options.value = ['Option A', 'Option B', 'Option B2'];\n        searchQuery.value = 'b ';\n        useSetup(() => {\n          const { normalizedOptions } = useFetchsOptions(\n            localValue,\n            options,\n            textAttribute,\n            valueAttribute,\n            normalize,\n            searchQuery,\n            fetchFn,\n            prefetchFn,\n            fetchDelay,\n            fetchMinimumInputLength,\n            fetchMinimumInputLengthText,\n          );\n\n          expect(normalizedOptions.value).toEqual([\n            { raw: 'Option B', text: 'Option B', value: 'Option B' },\n            { raw: 'Option B2', text: 'Option B2', value: 'Option B2' },\n          ]);\n        });\n      });\n    });\n  });\n\n  describe('with fetch function', () => {\n    beforeEach(() => {\n      options.value = [];\n      fetchFn.value = () => new Promise((resolve) => resolve({\n        results: ['A', 'B'],\n      }));\n      fetchDelay.value = 0;\n      jest.useFakeTimers();\n    });\n\n    afterEach(() => {\n      jest.useRealTimers();\n    });\n\n    it('should emit an error event if the response doesnt have results', () => {\n      fetchFn.value = () => new Promise((resolve) => {\n        resolve({\n          wrong: 'sss',\n        } as any);\n      });\n\n      useSetup(() => {\n        const { fetchOptions } = useFetchsOptions(\n          localValue,\n          options,\n          textAttribute,\n          valueAttribute,\n          normalize,\n          searchQuery,\n          fetchFn,\n          prefetchFn,\n          fetchDelay,\n          fetchMinimumInputLength,\n          fetchMinimumInputLengthText,\n        );\n\n        fetchOptions();\n      }, {}, {\n        onFetchOptionsError: (error: any) => {\n          expect(error).toBeInstanceOf(Error);\n          expect(error.toString()).toBe('Error: Options response must be an object with `results` property.');\n        },\n      });\n    });\n\n    it('should emit an error event if the response results are in an invalid format', () => {\n      fetchFn.value = () => new Promise((resolve) => {\n        resolve({\n          results: 'invalid format',\n        } as any);\n      });\n\n      useSetup(() => {\n        const { fetchOptions } = useFetchsOptions(\n          localValue,\n          options,\n          textAttribute,\n          valueAttribute,\n          normalize,\n          searchQuery,\n          fetchFn,\n          prefetchFn,\n          fetchDelay,\n          fetchMinimumInputLength,\n          fetchMinimumInputLengthText,\n        );\n\n        fetchOptions();\n      }, {}, {\n        onFetchOptionsError: (error: any) => {\n          expect(error).toBeInstanceOf(Error);\n          expect(error.toString()).toBe('Error: Response.results must be an array or object, got string');\n        },\n      });\n    });\n\n    it('returns normalized options', () => {\n      useSetup(async () => {\n        const { normalizedOptions, fetchOptions } = useFetchsOptions(\n          localValue,\n          options,\n          textAttribute,\n          valueAttribute,\n          normalize,\n          searchQuery,\n          fetchFn,\n          prefetchFn,\n          fetchDelay,\n          fetchMinimumInputLength,\n          fetchMinimumInputLengthText,\n        );\n\n        expect(normalizedOptions.value).toEqual([]);\n\n        fetchOptions();\n\n        await nextTick();\n\n        expect(normalizedOptions.value).toEqual([\n          { raw: 'A', text: 'A', value: 'A' },\n          { raw: 'B', text: 'B', value: 'B' },\n        ]);\n      });\n    });\n\n    it('determines that is fetching options is promise is busy', () => {\n      useSetup(async () => {\n        jest.useFakeTimers();\n\n        fetchFn.value = () => new Promise((resolve) => {\n          setTimeout(() => {\n            resolve({\n              results: ['A', 'B'],\n            });\n          }, 10);\n        });\n\n        const { fetchingOptions, fetchOptions } = useFetchsOptions(\n          localValue,\n          options,\n          textAttribute,\n          valueAttribute,\n          normalize,\n          searchQuery,\n          fetchFn,\n          prefetchFn,\n          fetchDelay,\n          fetchMinimumInputLength,\n          fetchMinimumInputLengthText,\n        );\n\n        expect(fetchingOptions.value).toBe(false);\n\n        fetchOptions();\n        await nextTick();\n        expect(fetchingOptions.value).toBe(true);\n\n        jest.advanceTimersByTime(9);\n        await nextTick();\n        expect(fetchingOptions.value).toBe(true);\n\n        jest.advanceTimersByTime(1);\n        await nextTick();\n        expect(fetchingOptions.value).toBe(false);\n\n        jest.useRealTimers();\n      });\n    });\n\n    it('determines if the fetched options have more pages', () => {\n      useSetup(async () => {\n        fetchFn.value = () => new Promise((resolve) => {\n          resolve({\n            results: ['A', 'B'],\n            hasMorePages: true,\n          });\n        });\n\n        const { fetchedOptionsHaveMorePages, fetchOptions } = useFetchsOptions(\n          localValue,\n          options,\n          textAttribute,\n          valueAttribute,\n          normalize,\n          searchQuery,\n          fetchFn,\n          prefetchFn,\n          fetchDelay,\n          fetchMinimumInputLength,\n          fetchMinimumInputLengthText,\n        );\n\n        fetchOptions();\n\n        await nextTick();\n\n        expect(fetchedOptionsHaveMorePages.value).toBe(true);\n      });\n    });\n\n    it('determines if the fetched options doesnt have more pages', () => {\n      useSetup(() => {\n        fetchFn.value = () => new Promise((resolve) => {\n          resolve({\n            results: ['A', 'B'],\n            hasMorePages: false,\n          });\n        });\n\n        const { fetchedOptionsHaveMorePages, fetchOptions } = useFetchsOptions(\n          localValue,\n          options,\n          textAttribute,\n          valueAttribute,\n          normalize,\n          searchQuery,\n          fetchFn,\n          prefetchFn,\n          fetchDelay,\n          fetchMinimumInputLength,\n          fetchMinimumInputLengthText,\n        );\n\n        fetchOptions();\n\n        expect(fetchedOptionsHaveMorePages.value).toBe(false);\n      });\n    });\n\n    it('determines if the options were fetched', () => {\n      useSetup(async () => {\n        fetchFn.value = () => new Promise((resolve) => {\n          resolve({\n            results: ['A', 'B'],\n            hasMorePages: false,\n          });\n        });\n\n        const { optionsWereFetched, fetchOptions } = useFetchsOptions(\n          localValue,\n          options,\n          textAttribute,\n          valueAttribute,\n          normalize,\n          searchQuery,\n          fetchFn,\n          prefetchFn,\n          fetchDelay,\n          fetchMinimumInputLength,\n          fetchMinimumInputLengthText,\n        );\n\n        expect(optionsWereFetched.value).toBe(false);\n\n        fetchOptions();\n\n        await nextTick();\n\n        expect(optionsWereFetched.value).toBe(true);\n      });\n    });\n\n    it('resets the optionsWereFetched flag if search query changes', () => {\n      useSetup(async () => {\n        fetchFn.value = () => new Promise((resolve) => {\n          resolve({\n            results: ['A', 'B'],\n            hasMorePages: false,\n          });\n        });\n\n        const { optionsWereFetched, fetchOptions } = useFetchsOptions(\n          localValue,\n          options,\n          textAttribute,\n          valueAttribute,\n          normalize,\n          searchQuery,\n          fetchFn,\n          prefetchFn,\n          fetchDelay,\n          fetchMinimumInputLength,\n          fetchMinimumInputLengthText,\n        );\n        expect(optionsWereFetched.value).toBe(false);\n\n        fetchOptions();\n\n        await nextTick();\n\n        expect(optionsWereFetched.value).toBe(true);\n\n        searchQuery.value = 'other';\n\n        await nextTick();\n\n        expect(optionsWereFetched.value).toBe(false);\n\n        fetchOptions();\n\n        await nextTick();\n\n        expect(optionsWereFetched.value).toBe(true);\n      });\n    });\n\n    it('doesnt resets the optionsWereFetched flag if search query doesnt have enough characters', () => {\n      useSetup(async () => {\n        fetchFn.value = () => new Promise((resolve) => {\n          resolve({\n            results: ['A', 'B'],\n            hasMorePages: false,\n          });\n        });\n\n        fetchMinimumInputLength.value = 3;\n\n        const { optionsWereFetched, fetchOptions } = useFetchsOptions(\n          localValue,\n          options,\n          textAttribute,\n          valueAttribute,\n          normalize,\n          searchQuery,\n          fetchFn,\n          prefetchFn,\n          fetchDelay,\n          fetchMinimumInputLength,\n          fetchMinimumInputLengthText,\n        );\n        expect(optionsWereFetched.value).toBe(false);\n\n        fetchOptions();\n\n        await nextTick();\n\n        expect(optionsWereFetched.value).toBe(true);\n\n        searchQuery.value = 'te';\n\n        await nextTick();\n\n        expect(optionsWereFetched.value).toBe(true);\n\n        searchQuery.value = 'tes';\n\n        await nextTick();\n\n        expect(optionsWereFetched.value).toBe(false);\n      });\n    });\n\n    it('doesnt resets the optionsWereFetched flag if no fetchFn', () => {\n      useSetup(() => {\n        fetchFn.value = undefined;\n\n        const { optionsWereFetched, fetchOptions } = useFetchsOptions(\n          localValue,\n          options,\n          textAttribute,\n          valueAttribute,\n          normalize,\n          searchQuery,\n          fetchFn,\n          prefetchFn,\n          fetchDelay,\n          fetchMinimumInputLength,\n          fetchMinimumInputLengthText,\n        );\n        expect(optionsWereFetched.value).toBe(false);\n\n        fetchOptions();\n\n        expect(optionsWereFetched.value).toBe(false);\n      });\n    });\n\n    it('handles undefined options', () => {\n      useSetup(async () => {\n        fetchFn.value = () => new Promise((resolve) => resolve({\n          results: undefined!,\n        }));\n\n        const { fetchOptions, normalizedOptions } = useFetchsOptions(\n          localValue,\n          options,\n          textAttribute,\n          valueAttribute,\n          normalize,\n          searchQuery,\n          fetchFn,\n          prefetchFn,\n          fetchDelay,\n          fetchMinimumInputLength,\n          fetchMinimumInputLengthText,\n        );\n\n        expect(normalizedOptions.value).toEqual([]);\n\n        fetchOptions();\n\n        await nextTick();\n\n        expect(normalizedOptions.value).toEqual([\n          { raw: 'A', text: 'A', value: 'A' },\n          { raw: 'B', text: 'B', value: 'B' },\n        ]);\n      });\n    });\n\n    it('accepts a custom `textAttribute`', () => {\n      useSetup(async () => {\n        fetchFn.value = () => new Promise((resolve) => resolve({\n          results: [\n            { label: 'Letter A', value: 'A' },\n            { label: 'Letter B', value: 'B' },\n          ],\n        }));\n\n        const { normalizedOptions, fetchOptions } = useFetchsOptions(\n          localValue,\n          options,\n          ref('label'),\n          valueAttribute,\n          normalize,\n          searchQuery,\n          fetchFn,\n          prefetchFn,\n          fetchDelay,\n          fetchMinimumInputLength,\n          fetchMinimumInputLengthText,\n        );\n\n        expect(normalizedOptions.value).toEqual([]);\n\n        fetchOptions();\n\n        await nextTick();\n\n        expect(normalizedOptions.value).toEqual([\n          { raw: { label: 'Letter A', value: 'A' }, text: 'Letter A', value: 'A' },\n          { raw: { label: 'Letter B', value: 'B' }, text: 'Letter B', value: 'B' },\n        ]);\n      });\n    });\n\n    it('accepts a custom `valueAttribute`', () => {\n      useSetup(async () => {\n        fetchFn.value = () => new Promise((resolve) => resolve({\n          results: [\n            { text: 'A', identifier: 'a' },\n            { text: 'B', identifier: 'b' },\n          ],\n        }));\n\n        const { normalizedOptions, fetchOptions } = useFetchsOptions(\n          localValue,\n          options,\n          textAttribute,\n          ref('identifier'),\n          normalize,\n          searchQuery,\n          fetchFn,\n          prefetchFn,\n          fetchDelay,\n          fetchMinimumInputLength,\n          fetchMinimumInputLengthText,\n        );\n\n        expect(normalizedOptions.value).toEqual([]);\n\n        fetchOptions();\n\n        await nextTick();\n\n        expect(normalizedOptions.value).toEqual([\n          { raw: { text: 'A', identifier: 'a' }, text: 'A', value: 'a' },\n          { raw: { text: 'B', identifier: 'b' }, text: 'B', value: 'b' },\n        ]);\n      });\n    });\n\n    it('doesnt normalize the options if normalize is `false`', () => {\n      useSetup(async () => {\n        const { normalizedOptions, fetchOptions } = useFetchsOptions(\n          localValue,\n          options,\n          textAttribute,\n          valueAttribute,\n          ref(false),\n          searchQuery,\n          fetchFn,\n          prefetchFn,\n          fetchDelay,\n          fetchMinimumInputLength,\n          fetchMinimumInputLengthText,\n        );\n\n        expect(normalizedOptions.value).toEqual([]);\n\n        fetchOptions();\n\n        await nextTick();\n\n        expect(normalizedOptions.value).toEqual(options.value);\n      });\n    });\n\n    describe('with a custom delay', () => {\n      beforeEach(() => {\n        fetchDelay.value = 200;\n        jest.useFakeTimers();\n      });\n\n      afterEach(() => {\n        jest.useRealTimers();\n      });\n\n      it('fetchs after 200ms', () => {\n        const fetchFunctionMock = jest.fn().mockImplementation(() => new Promise((resolve) => {\n          resolve({\n            results: ['A', 'B'],\n            hasMorePages: false,\n          });\n        }));\n\n        fetchFn.value = fetchFunctionMock;\n\n        searchQuery.value = 'test ';\n\n        useSetup(async () => {\n          const { normalizedOptions, fetchOptions } = useFetchsOptions(\n            localValue,\n            options,\n            textAttribute,\n            valueAttribute,\n            normalize,\n            searchQuery,\n            fetchFn,\n            prefetchFn,\n            fetchDelay,\n            fetchMinimumInputLength,\n            fetchMinimumInputLengthText,\n          );\n\n          expect(normalizedOptions.value).toEqual([]);\n\n          fetchOptions();\n\n          await nextTick();\n\n          expect(fetchFunctionMock).not.toHaveBeenCalled();\n\n          jest.advanceTimersByTime(199);\n\n          await nextTick();\n\n          expect(fetchFunctionMock).not.toHaveBeenCalled();\n\n          jest.advanceTimersByTime(1);\n\n          await nextTick();\n\n          expect(fetchFunctionMock).toHaveBeenCalled();\n        });\n      });\n\n      it('throtles the search', () => {\n        const fetchFunctionMock = jest.fn().mockImplementation(() => new Promise((resolve) => {\n          resolve({\n            results: ['A', 'B'],\n            hasMorePages: false,\n          });\n        }));\n\n        fetchFn.value = fetchFunctionMock;\n\n        searchQuery.value = 'test ';\n\n        useSetup(async () => {\n          const { normalizedOptions, fetchOptions } = useFetchsOptions(\n            localValue,\n            options,\n            textAttribute,\n            valueAttribute,\n            normalize,\n            searchQuery,\n            fetchFn,\n            prefetchFn,\n            fetchDelay,\n            fetchMinimumInputLength,\n            fetchMinimumInputLengthText,\n          );\n\n          expect(normalizedOptions.value).toEqual([]);\n\n          fetchOptions();\n\n          await nextTick();\n\n          expect(fetchFunctionMock).not.toHaveBeenCalled();\n\n          jest.advanceTimersByTime(199);\n\n          await nextTick();\n\n          expect(fetchFunctionMock).not.toHaveBeenCalled();\n\n          // Since its throttled it will reset the counter\n          fetchOptions();\n\n          jest.advanceTimersByTime(199);\n\n          await nextTick();\n\n          expect(fetchFunctionMock).not.toHaveBeenCalled();\n\n          jest.advanceTimersByTime(1);\n\n          await nextTick();\n\n          expect(fetchFunctionMock).toHaveBeenCalled();\n        });\n      });\n    });\n\n    describe('with a minimum input length', () => {\n      beforeEach(() => {\n        fetchMinimumInputLength.value = 3;\n      });\n\n      it('doesnt fetch if no query', () => {\n        const fetchFunctionMock = jest.fn().mockImplementation(() => new Promise((resolve) => {\n          resolve({\n            results: ['A', 'B'],\n            hasMorePages: false,\n          });\n        }));\n\n        fetchFn.value = fetchFunctionMock;\n\n        useSetup(async () => {\n          const { normalizedOptions } = useFetchsOptions(\n            localValue,\n            options,\n            textAttribute,\n            valueAttribute,\n            normalize,\n            searchQuery,\n            fetchFn,\n            prefetchFn,\n            fetchDelay,\n            fetchMinimumInputLength,\n            fetchMinimumInputLengthText,\n          );\n\n          expect(normalizedOptions.value).toEqual([]);\n\n          searchQuery.value = '';\n\n          await nextTick();\n\n          expect(fetchFunctionMock).not.toHaveBeenCalled();\n        });\n      });\n\n      it('determines that needsMoreCharsToFetch if query is shorter that the min input length', () => {\n        const fetchFunctionMock = jest.fn().mockImplementation(() => new Promise((resolve) => {\n          resolve({\n            results: ['A', 'B'],\n            hasMorePages: false,\n          });\n        }));\n\n        fetchFn.value = fetchFunctionMock;\n\n        searchQuery.value = 'te';\n\n        useSetup(() => {\n          const { needsMoreCharsToFetch } = useFetchsOptions(\n            localValue,\n            options,\n            textAttribute,\n            valueAttribute,\n            normalize,\n            searchQuery,\n            fetchFn,\n            prefetchFn,\n            fetchDelay,\n            fetchMinimumInputLength,\n            fetchMinimumInputLengthText,\n          );\n\n          expect(needsMoreCharsToFetch.value).toBe(true);\n        });\n      });\n\n      it('determines that doesnt needsMoreCharsToFetch if not fetchFn', () => {\n        fetchFn.value = undefined;\n\n        searchQuery.value = 'test';\n\n        useSetup(() => {\n          const { needsMoreCharsToFetch } = useFetchsOptions(\n            localValue,\n            options,\n            textAttribute,\n            valueAttribute,\n            normalize,\n            searchQuery,\n            fetchFn,\n            prefetchFn,\n            fetchDelay,\n            fetchMinimumInputLength,\n            fetchMinimumInputLengthText,\n          );\n\n          expect(needsMoreCharsToFetch.value).toBe(false);\n        });\n      });\n\n      it('determines that doesnt needsMoreCharsToFetch if query is exactly the min input length', () => {\n        const fetchFunctionMock = jest.fn().mockImplementation(() => new Promise((resolve) => {\n          resolve({\n            results: ['A', 'B'],\n            hasMorePages: false,\n          });\n        }));\n\n        fetchFn.value = fetchFunctionMock;\n\n        searchQuery.value = 'tes';\n\n        useSetup(() => {\n          const { needsMoreCharsToFetch } = useFetchsOptions(\n            localValue,\n            options,\n            textAttribute,\n            valueAttribute,\n            normalize,\n            searchQuery,\n            fetchFn,\n            prefetchFn,\n            fetchDelay,\n            fetchMinimumInputLength,\n            fetchMinimumInputLengthText,\n          );\n\n          expect(needsMoreCharsToFetch.value).toBe(false);\n        });\n      });\n\n      it('doesnt fetch if the query is shorter than the min input length', () => {\n        const fetchFunctionMock = jest.fn().mockImplementation(() => new Promise((resolve) => {\n          resolve({\n            results: ['A', 'B'],\n            hasMorePages: false,\n          });\n        }));\n\n        fetchFn.value = fetchFunctionMock;\n\n        useSetup(async () => {\n          const { normalizedOptions } = useFetchsOptions(\n            localValue,\n            options,\n            textAttribute,\n            valueAttribute,\n            normalize,\n            searchQuery,\n            fetchFn,\n            prefetchFn,\n            fetchDelay,\n            fetchMinimumInputLength,\n            fetchMinimumInputLengthText,\n          );\n\n          expect(normalizedOptions.value).toEqual([]);\n\n          searchQuery.value = 'te';\n\n          await nextTick();\n\n          expect(fetchFunctionMock).not.toHaveBeenCalled();\n        });\n      });\n\n      it('fetchs if the query is exactly the min input length', () => {\n        const fetchFunctionMock = jest.fn().mockImplementation(() => new Promise((resolve) => {\n          resolve({\n            results: ['A', 'B'],\n            hasMorePages: false,\n          });\n        }));\n\n        fetchFn.value = fetchFunctionMock;\n\n        useSetup(async () => {\n          const { normalizedOptions } = useFetchsOptions(\n            localValue,\n            options,\n            textAttribute,\n            valueAttribute,\n            normalize,\n            searchQuery,\n            fetchFn,\n            prefetchFn,\n            fetchDelay,\n            fetchMinimumInputLength,\n            fetchMinimumInputLengthText,\n          );\n\n          expect(normalizedOptions.value).toEqual([]);\n\n          searchQuery.value = 'tes';\n\n          await nextTick();\n\n          expect(fetchFunctionMock).toHaveBeenCalled();\n        });\n      });\n\n      it('fetchs if the query is larger that the min input length', () => {\n        const fetchFunctionMock = jest.fn().mockImplementation(() => new Promise((resolve) => {\n          resolve({\n            results: ['A', 'B'],\n            hasMorePages: false,\n          });\n        }));\n\n        fetchFn.value = fetchFunctionMock;\n\n        searchQuery.value = 'te';\n\n        useSetup(async () => {\n          const { normalizedOptions, fetchOptions } = useFetchsOptions(\n            localValue,\n            options,\n            textAttribute,\n            valueAttribute,\n            normalize,\n            searchQuery,\n            fetchFn,\n            prefetchFn,\n            fetchDelay,\n            fetchMinimumInputLength,\n            fetchMinimumInputLengthText,\n          );\n\n          expect(normalizedOptions.value).toEqual([]);\n\n          fetchOptions();\n\n          await nextTick();\n\n          expect(fetchFunctionMock).toHaveBeenCalled();\n        });\n      });\n\n      it('builds the fetch minimum input length text', () => {\n        useSetup(() => {\n          const { needsMoreCharsMessage } = useFetchsOptions(\n            localValue,\n            options,\n            textAttribute,\n            valueAttribute,\n            normalize,\n            searchQuery,\n            fetchFn,\n            prefetchFn,\n            fetchDelay,\n            fetchMinimumInputLength,\n            fetchMinimumInputLengthText,\n          );\n\n          expect(needsMoreCharsMessage.value).toBe('Please enter 3 or more characters');\n        });\n      });\n\n      it('accepts a string as the minimum input length text', () => {\n        fetchMinimumInputLengthText.value = 'test';\n        useSetup(() => {\n          const { needsMoreCharsMessage } = useFetchsOptions(\n            localValue,\n            options,\n            textAttribute,\n            valueAttribute,\n            normalize,\n            searchQuery,\n            fetchFn,\n            prefetchFn,\n            fetchDelay,\n            fetchMinimumInputLength,\n            fetchMinimumInputLengthText,\n          );\n\n          expect(needsMoreCharsMessage.value).toBe('test');\n        });\n      });\n\n      it('pass the minimum input length text and the query to the fetchMinimumInputLengthText function ', () => {\n        const fetchMinimumInputLengthTextMock = jest.fn().mockImplementation(() => 'test');\n\n        fetchMinimumInputLengthText.value = fetchMinimumInputLengthTextMock;\n\n        searchQuery.value = 'te';\n\n        useSetup(() => {\n          const { needsMoreCharsMessage } = useFetchsOptions(\n            localValue,\n            options,\n            textAttribute,\n            valueAttribute,\n            normalize,\n            searchQuery,\n            fetchFn,\n            prefetchFn,\n            fetchDelay,\n            fetchMinimumInputLength,\n            fetchMinimumInputLengthText,\n          );\n\n          expect(needsMoreCharsMessage.value).toBe('test');\n\n          expect(fetchMinimumInputLengthTextMock).toHaveBeenCalledWith(3, 'te');\n        });\n      });\n    });\n\n    describe('with search query', () => {\n      it('filters by the search query', () => {\n        const fetchFunctionMock = jest.fn();\n\n        fetchFn.value = fetchFunctionMock.mockImplementation(() => new Promise((resolve) => {\n          resolve({\n            results: ['A', 'B'],\n            hasMorePages: false,\n          });\n        }));\n\n        searchQuery.value = 'test ';\n\n        useSetup(async () => {\n          const { normalizedOptions, fetchOptions } = useFetchsOptions(\n            localValue,\n            options,\n            textAttribute,\n            valueAttribute,\n            normalize,\n            searchQuery,\n            fetchFn,\n            prefetchFn,\n            fetchDelay,\n            fetchMinimumInputLength,\n            fetchMinimumInputLengthText,\n          );\n\n          expect(normalizedOptions.value).toEqual([]);\n\n          fetchOptions();\n\n          await nextTick();\n\n          expect(fetchFunctionMock).toHaveBeenCalledWith('test ');\n        });\n      });\n    });\n  });\n\n  describe('with prefetch function', () => {\n    beforeEach(() => {\n      options.value = [];\n      prefetchFn.value = () => new Promise((resolve) => resolve(\n        ['A', 'B'],\n      ));\n    });\n\n    it('should emit an error event if the results are in an invalid format', () => {\n      prefetchFn.value = () => new Promise((resolve) => {\n        resolve('wrong' as any);\n      });\n\n      useSetup(() => {\n        const { prefetchOptions } = useFetchsOptions(\n          localValue,\n          options,\n          textAttribute,\n          valueAttribute,\n          normalize,\n          searchQuery,\n          fetchFn,\n          prefetchFn,\n          fetchDelay,\n          fetchMinimumInputLength,\n          fetchMinimumInputLengthText,\n        );\n\n        prefetchOptions();\n      }, {}, {\n        onFetchOptionsError: (error: any) => {\n          expect(error).toBeInstanceOf(Error);\n          expect(error.toString()).toBe('Error: Response must be an array or object, got string');\n        },\n      });\n    });\n\n    it('returns normalized options', () => {\n      useSetup(async () => {\n        const { normalizedOptions, prefetchOptions } = useFetchsOptions(\n          localValue,\n          options,\n          textAttribute,\n          valueAttribute,\n          normalize,\n          searchQuery,\n          fetchFn,\n          prefetchFn,\n          fetchDelay,\n          fetchMinimumInputLength,\n          fetchMinimumInputLengthText,\n        );\n\n        expect(normalizedOptions.value).toEqual([]);\n\n        prefetchOptions();\n\n        await nextTick();\n\n        expect(normalizedOptions.value).toEqual([\n          { raw: 'A', text: 'A', value: 'A' },\n          { raw: 'B', text: 'B', value: 'B' },\n        ]);\n      });\n    });\n\n    it('determines that is fetching options if promise is busy', () => {\n      useSetup(async () => {\n        jest.useFakeTimers();\n\n        prefetchFn.value = () => new Promise((resolve) => {\n          setTimeout(() => {\n            resolve(['A', 'B']);\n          }, 10);\n        });\n\n        const { fetchingOptions, prefetchOptions } = useFetchsOptions(\n          localValue,\n          options,\n          textAttribute,\n          valueAttribute,\n          normalize,\n          searchQuery,\n          fetchFn,\n          prefetchFn,\n          fetchDelay,\n          fetchMinimumInputLength,\n          fetchMinimumInputLengthText,\n        );\n\n        expect(fetchingOptions.value).toBe(false);\n\n        prefetchOptions();\n        await nextTick();\n        expect(fetchingOptions.value).toBe(true);\n\n        jest.advanceTimersByTime(9);\n        await nextTick();\n        expect(fetchingOptions.value).toBe(true);\n\n        jest.advanceTimersByTime(1);\n        await nextTick();\n        expect(fetchingOptions.value).toBe(false);\n\n        jest.useRealTimers();\n      });\n    });\n\n    it('determines if the options were fetched', () => {\n      useSetup(async () => {\n        prefetchFn.value = () => new Promise((resolve) => {\n          resolve(['A', 'B']);\n        });\n\n        const { optionsWereFetched, prefetchOptions } = useFetchsOptions(\n          localValue,\n          options,\n          textAttribute,\n          valueAttribute,\n          normalize,\n          searchQuery,\n          fetchFn,\n          prefetchFn,\n          fetchDelay,\n          fetchMinimumInputLength,\n          fetchMinimumInputLengthText,\n        );\n\n        expect(optionsWereFetched.value).toBe(false);\n\n        prefetchOptions();\n\n        await nextTick();\n\n        expect(optionsWereFetched.value).toBe(true);\n      });\n    });\n\n    it('doesnt resets the optionsWereFetched flag if no fetchFn', () => {\n      useSetup(() => {\n        prefetchFn.value = false;\n\n        const { optionsWereFetched, prefetchOptions } = useFetchsOptions(\n          localValue,\n          options,\n          textAttribute,\n          valueAttribute,\n          normalize,\n          searchQuery,\n          fetchFn,\n          prefetchFn,\n          fetchDelay,\n          fetchMinimumInputLength,\n          fetchMinimumInputLengthText,\n        );\n        expect(optionsWereFetched.value).toBe(false);\n\n        prefetchOptions();\n\n        expect(optionsWereFetched.value).toBe(false);\n      });\n    });\n\n    it('accepts a custom `textAttribute`', () => {\n      useSetup(async () => {\n        prefetchFn.value = () => new Promise((resolve) => resolve([\n          { label: 'Letter A', value: 'A' },\n          { label: 'Letter B', value: 'B' },\n        ]));\n\n        const { normalizedOptions, prefetchOptions } = useFetchsOptions(\n          localValue,\n          options,\n          ref('label'),\n          valueAttribute,\n          normalize,\n          searchQuery,\n          fetchFn,\n          prefetchFn,\n          fetchDelay,\n          fetchMinimumInputLength,\n          fetchMinimumInputLengthText,\n        );\n\n        expect(normalizedOptions.value).toEqual([]);\n\n        prefetchOptions();\n\n        await nextTick();\n\n        expect(normalizedOptions.value).toEqual([\n          { raw: { label: 'Letter A', value: 'A' }, text: 'Letter A', value: 'A' },\n          { raw: { label: 'Letter B', value: 'B' }, text: 'Letter B', value: 'B' },\n        ]);\n      });\n    });\n\n    it('accepts a custom `valueAttribute`', () => {\n      useSetup(async () => {\n        prefetchFn.value = () => new Promise((resolve) => resolve([\n          { text: 'A', identifier: 'a' },\n          { text: 'B', identifier: 'b' },\n        ]));\n\n        const { normalizedOptions, prefetchOptions } = useFetchsOptions(\n          localValue,\n          options,\n          textAttribute,\n          ref('identifier'),\n          normalize,\n          searchQuery,\n          fetchFn,\n          prefetchFn,\n          fetchDelay,\n          fetchMinimumInputLength,\n          fetchMinimumInputLengthText,\n        );\n\n        expect(normalizedOptions.value).toEqual([]);\n\n        prefetchOptions();\n\n        await nextTick();\n\n        expect(normalizedOptions.value).toEqual([\n          { raw: { text: 'A', identifier: 'a' }, text: 'A', value: 'a' },\n          { raw: { text: 'B', identifier: 'b' }, text: 'B', value: 'b' },\n        ]);\n      });\n    });\n\n    it('doesnt normalize the options if normalize is `false`', () => {\n      useSetup(async () => {\n        const { normalizedOptions, prefetchOptions } = useFetchsOptions(\n          localValue,\n          options,\n          textAttribute,\n          valueAttribute,\n          ref(false),\n          searchQuery,\n          fetchFn,\n          prefetchFn,\n          fetchDelay,\n          fetchMinimumInputLength,\n          fetchMinimumInputLengthText,\n        );\n\n        expect(normalizedOptions.value).toEqual([]);\n\n        prefetchOptions();\n\n        await nextTick();\n\n        expect(normalizedOptions.value).toEqual(options.value);\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "src/__tests/use/useInjectsClassesList.spec.ts",
    "content": "import { shallowMount } from '@vue/test-utils';\nimport { defineComponent } from 'vue';\nimport useInjectsClassesList from '../../use/useInjectsClassesList';\n\ndescribe('useInjectsClassesList', () => {\n  const configurationToProvide = {\n    classesList: {\n      test: 'test',\n      foo: 'bar',\n    },\n  };\n\n  const component = defineComponent({\n    setup() {\n      const classesList = useInjectsClassesList();\n\n      return { classesList };\n    },\n    template: '<div />',\n  });\n\n  it('returns the provided configuration option', () => {\n    const wrapper = shallowMount(component, {\n      global: {\n        provide: {\n          configuration: configurationToProvide,\n        },\n      },\n    });\n\n    expect(wrapper.vm.classesList).toEqual(configurationToProvide.classesList);\n  });\n\n  it('returns empty object if classeslist are not provided', () => {\n    const wrapper = shallowMount(component);\n\n    expect(wrapper.vm.classesList).toEqual({});\n  });\n});\n"
  },
  {
    "path": "src/__tests/use/useInjectsConfiguration.spec.ts",
    "content": "import { shallowMount } from '@vue/test-utils';\nimport { defineComponent } from 'vue';\nimport useInjectsConfiguration from '../../use/useInjectsConfiguration';\n\ndescribe('useInjectsConfiguration', () => {\n  const configurationToProvide = {\n    name: 'test',\n    foo: 'bar',\n    classesList: {\n      test: 'test',\n    },\n  };\n\n  const component = defineComponent({\n    setup() {\n      const configuration = useInjectsConfiguration();\n\n      return { configuration };\n    },\n    template: '<div />',\n  });\n\n  it('returns the provided configuration option', () => {\n    const wrapper = shallowMount(component, {\n      global: {\n        provide: {\n          configuration: configurationToProvide,\n        },\n      },\n    });\n\n    expect(wrapper.vm.configuration).toEqual(configurationToProvide);\n  });\n\n  it('returns the an empty configuration if no provide', () => {\n    const wrapper = shallowMount(component);\n\n    expect(wrapper.vm.configuration).toEqual({});\n  });\n});\n"
  },
  {
    "path": "src/__tests/use/useMulipleableVModel.spec.ts",
    "content": "import useMulipleableVModel from '../../use/useMulipleableVModel';\nimport { useSetup } from './useSetup';\n\ndescribe('useMulipleableVModel.spec', () => {\n  it('should return an empty array if multiple and no value', () => {\n    const configuration = { multiple: true };\n    useSetup(() => {\n      const { localValue } = useMulipleableVModel({\n        modelValue: undefined,\n      }, 'modelValue', configuration);\n      expect(localValue.value).toEqual([]);\n    });\n  });\n\n  it('should return an array if multiple is an empty string', () => {\n    const configuration = { multiple: '' };\n\n    useSetup(() => {\n      const { localValue } = useMulipleableVModel({\n        modelValue: undefined,\n      }, 'modelValue', configuration);\n      expect(localValue.value).toEqual([]);\n    });\n  });\n  it('should return an array if multiple is `true` string', () => {\n    const configuration = { multiple: 'true' };\n    useSetup(() => {\n      const { localValue } = useMulipleableVModel({\n        modelValue: undefined,\n      }, 'modelValue', configuration);\n      expect(localValue.value).toEqual([]);\n    });\n  });\n\n  it('should return an array if multiple is `false` string', () => {\n    const configuration = { multiple: 'false' };\n    useSetup(() => {\n      const { localValue } = useMulipleableVModel({\n        modelValue: undefined,\n      }, 'modelValue', configuration);\n      expect(localValue.value).toEqual([]);\n    });\n  });\n\n  it('should return undefined if multiple is `false`', () => {\n    const configuration = { multiple: false };\n    useSetup(() => {\n      const { localValue } = useMulipleableVModel({\n        modelValue: undefined,\n      }, 'modelValue', configuration);\n      expect(localValue.value).toBeUndefined();\n    });\n  });\n\n  it('should return undefined if no configuration', () => {\n    useSetup(() => {\n      const { localValue } = useMulipleableVModel({\n        modelValue: undefined,\n      }, 'modelValue', undefined);\n      expect(localValue.value).toBeUndefined();\n    });\n  });\n\n  it('should return the default value when model changes to an undefined value', () => {\n    const configuration = {};\n\n    useSetup(() => {\n      const { localValue } = useMulipleableVModel({\n        modelValue: undefined,\n      }, 'modelValue', configuration);\n      expect(localValue.value).toBeUndefined();\n    });\n  });\n\n  it('should return the default value when no model defined when using multiple', () => {\n    const configuration = { multiple: true };\n\n    useSetup(() => {\n      const { localValue } = useMulipleableVModel({\n        modelValue: undefined,\n      }, 'modelValue', configuration);\n      expect(localValue.value).toEqual([]);\n    });\n  });\n});\n"
  },
  {
    "path": "src/__tests/use/useMultioptions.spec.ts",
    "content": "import { ref } from 'vue';\nimport useMultioptions from '../../use/useMultioptions';\nimport { useSetup } from './useSetup';\n\ndescribe('useMultioptions', () => {\n  const options = ref(['A', 'B']);\n  const textAttribute = ref(undefined);\n  const valueAttribute = ref(undefined);\n  const normalize = ref(true);\n  it('returns normalized options', () => {\n    useSetup(() => {\n      const { normalizedOptions } = useMultioptions(\n        options,\n        textAttribute,\n        valueAttribute,\n        normalize,\n      );\n\n      expect(normalizedOptions.value).toEqual([\n        { raw: 'A', text: 'A', value: 'A' },\n        { raw: 'B', text: 'B', value: 'B' },\n      ]);\n    });\n  });\n\n  it('returns flattened options', () => {\n    useSetup(() => {\n      const { flattenedOptions } = useMultioptions(\n        ref([\n          { text: 'A', value: 'A' },\n          {\n            text: 'B', value: 'B', children: ['C'],\n          },\n        ]),\n        textAttribute,\n        valueAttribute,\n        normalize,\n      );\n\n      expect(flattenedOptions.value).toEqual(\n        [\n          { value: 'A', text: 'A', raw: { text: 'A', value: 'A' } },\n          { value: 'C', text: 'C', raw: 'C' },\n        ],\n      );\n    });\n  });\n\n  it('handles undefined options', () => {\n    useSetup(() => {\n      const { normalizedOptions } = useMultioptions(\n        ref(undefined),\n        textAttribute,\n        valueAttribute,\n        normalize,\n      );\n\n      expect(normalizedOptions.value).toEqual([]);\n    });\n  });\n\n  it('accepts a custom `textAttribute`', () => {\n    useSetup(() => {\n      const { normalizedOptions } = useMultioptions(\n        ref([\n          { label: 'Letter A', value: 'A' },\n          { label: 'Letter B', value: 'B' },\n        ]),\n        ref('label'),\n        valueAttribute,\n        normalize,\n      );\n\n      expect(normalizedOptions.value).toEqual([\n        { raw: { label: 'Letter A', value: 'A' }, text: 'Letter A', value: 'A' },\n        { raw: { label: 'Letter B', value: 'B' }, text: 'Letter B', value: 'B' },\n      ]);\n    });\n  });\n\n  it('accepts a custom `valueAttribute`', () => {\n    useSetup(() => {\n      const { normalizedOptions } = useMultioptions(\n        ref([\n          { text: 'A', identifier: 'a' },\n          { text: 'B', identifier: 'b' },\n        ]),\n        textAttribute,\n        ref('identifier'),\n        normalize,\n      );\n\n      expect(normalizedOptions.value).toEqual([\n        { raw: { text: 'A', identifier: 'a' }, text: 'A', value: 'a' },\n        { raw: { text: 'B', identifier: 'b' }, text: 'B', value: 'b' },\n      ]);\n    });\n  });\n\n  it('doesnt normalize the options if normalize is `false`', () => {\n    useSetup(() => {\n      const { normalizedOptions } = useMultioptions(\n        options,\n        textAttribute,\n        valueAttribute,\n        ref(false),\n      );\n\n      expect(normalizedOptions.value).toEqual(options.value);\n    });\n  });\n});\n"
  },
  {
    "path": "src/__tests/use/useSelectableOption.spec.ts",
    "content": "/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { NormalizedOption } from '@variantjs/core';\nimport {\n  ComputedRef, computed, ref, Ref, nextTick,\n} from 'vue';\nimport useSelectableOption from '../../use/useSelectableOption';\n\ndescribe('useSelectableOption', () => {\n  const options: ComputedRef<NormalizedOption[]> = computed(() => [\n    { value: 'a', text: 'Option A' },\n    { value: 'b', text: 'Option B' },\n    { value: 'c', text: 'Option C' },\n  ]);\n\n  const localValue: Ref = ref(null);\n\n  const multiple: Ref<boolean> = ref(true);\n  const noMultiple: Ref<boolean> = ref(false);\n\n  beforeEach(() => {\n    localValue.value = null;\n  });\n\n  it('contains an selectedOption ref and selectOption, toggleOption, optionIsSelected methods', () => {\n    const {\n      selectedOption, selectOption, toggleOption, optionIsSelected,\n    } = useSelectableOption(\n      options,\n      localValue,\n      noMultiple,\n    );\n\n    expect(typeof selectedOption).toBe('object');\n    expect(typeof selectOption).toBe('function');\n    expect(typeof toggleOption).toBe('function');\n    expect(typeof optionIsSelected).toBe('function');\n  });\n\n  describe('selectedOption', () => {\n    it('returns undefined as the selected option if no local value', () => {\n      const {\n        selectedOption,\n      } = useSelectableOption(\n        options,\n        ref(null),\n        noMultiple,\n      );\n\n      expect(selectedOption.value).toBeUndefined();\n    });\n\n    it('returns undefined as the selected option if local value is not part of the options', () => {\n      const {\n        selectedOption,\n      } = useSelectableOption(\n        options,\n        ref('d'),\n        noMultiple,\n      );\n\n      expect(selectedOption.value).toBeUndefined();\n    });\n\n    it('returns the option that matchs the localValue', () => {\n      const {\n        selectedOption,\n      } = useSelectableOption(\n        options,\n        ref('b'),\n        noMultiple,\n      );\n\n      expect(selectedOption.value).toEqual({ value: 'b', text: 'Option B' });\n    });\n\n    it('returns all the options that match the localValue when multiple', () => {\n      const {\n        selectedOption,\n      } = useSelectableOption(\n        options,\n        ref(['b', 'c']),\n        ref(true),\n      );\n\n      expect(selectedOption.value).toEqual(\n        [\n          { value: 'b', text: 'Option B' },\n          { value: 'c', text: 'Option C' },\n        ],\n      );\n    });\n\n    it('returns an empty array if no localValue when multiple', () => {\n      const {\n        selectedOption,\n      } = useSelectableOption(\n        options,\n        ref(null),\n        ref(true),\n      );\n\n      expect(selectedOption.value).toEqual([]);\n    });\n\n    it('sets the selected options from the old selected options list ', async () => {\n      const value = ref<any>(null);\n\n      const {\n        selectedOption,\n      } = useSelectableOption(\n        options,\n        value,\n        ref(true),\n      );\n\n      selectedOption.value = [\n        { value: 'b', text: 'Option BA' },\n      ];\n\n      value.value = ['b'];\n\n      await nextTick();\n\n      expect(selectedOption.value).toEqual([\n        { value: 'b', text: 'Option BA' },\n      ]);\n    });\n\n    it('sets the selected options from the options list when it also have old selected options ', async () => {\n      const value = ref<any>(null);\n\n      const {\n        selectedOption,\n      } = useSelectableOption(\n        options,\n        value,\n        ref(true),\n      );\n\n      selectedOption.value = [\n        { value: 'f', text: 'Option F' },\n      ];\n\n      value.value = ['b'];\n\n      await nextTick();\n\n      expect(selectedOption.value).toEqual([\n        options.value[1],\n      ]);\n    });\n\n    it('sets the selected options from the options list ', async () => {\n      const value = ref<any>(null);\n\n      const {\n        selectedOption,\n      } = useSelectableOption(\n        options,\n        value,\n        ref(true),\n      );\n\n      selectedOption.value = undefined;\n\n      value.value = ['b'];\n\n      await nextTick();\n\n      expect(selectedOption.value).toEqual([\n        options.value[1],\n      ]);\n    });\n  });\n\n  describe('selectOption method', () => {\n    describe('when working with regular configuration (not multiple)', () => {\n      it('selects the option', () => {\n        const {\n          selectOption,\n        } = useSelectableOption(\n          options,\n          localValue,\n          noMultiple,\n        );\n\n        selectOption({ ...options.value[1] });\n        expect(localValue.value).toBe('b');\n      });\n\n      it('selects the option when localValue is an array', () => {\n        localValue.value = ['b'];\n\n        const {\n          selectOption,\n        } = useSelectableOption(\n          options,\n          localValue,\n          noMultiple,\n        );\n\n        selectOption({ ...options.value[1] });\n        expect(localValue.value).toBe('b');\n      });\n\n      it('doesnt do anything if option is selected', () => {\n        const {\n          selectOption,\n        } = useSelectableOption(\n          options,\n          localValue,\n          noMultiple,\n        );\n\n        selectOption({ ...options.value[1] });\n        expect(localValue.value).toBe('b');\n      });\n    });\n\n    describe('when working with multiple values', () => {\n      it('selects the option when localValue is some random value', () => {\n        localValue.value = 'b';\n        const {\n          selectOption,\n        } = useSelectableOption(\n          options,\n          localValue,\n          multiple,\n        );\n\n        selectOption({ ...options.value[1] });\n        expect(localValue.value).toEqual(['b']);\n      });\n\n      it('adds the option when localValue is empty array', () => {\n        localValue.value = [];\n\n        const {\n          selectOption,\n        } = useSelectableOption(\n          options,\n          localValue,\n          multiple,\n        );\n\n        selectOption({ ...options.value[1] });\n        expect(localValue.value).toEqual(['b']);\n      });\n\n      it('adds the option ', () => {\n        localValue.value = ['a'];\n\n        const {\n          selectOption,\n        } = useSelectableOption(\n          options,\n          localValue,\n          multiple,\n        );\n\n        selectOption({ ...options.value[1] });\n        expect(localValue.value).toEqual(['a', 'b']);\n      });\n\n      it('doesnt do anything if option is already selected', () => {\n        localValue.value = ['b'];\n        const {\n          selectOption,\n        } = useSelectableOption(\n          options,\n          localValue,\n          multiple,\n        );\n\n        selectOption({ ...options.value[1] });\n        expect(localValue.value).toEqual(['b']);\n      });\n    });\n  });\n\n  describe('toggleOption method', () => {\n    describe('when working with regular configuration (not multiple)', () => {\n      it('selects the option if not selected', () => {\n        const {\n          toggleOption,\n        } = useSelectableOption(\n          options,\n          localValue,\n          noMultiple,\n        );\n\n        toggleOption({ ...options.value[1] });\n        expect(localValue.value).toBe('b');\n      });\n\n      it('selects the option when localValue is an array', () => {\n        localValue.value = ['b'];\n\n        const {\n          toggleOption,\n        } = useSelectableOption(\n          options,\n          localValue,\n          noMultiple,\n        );\n\n        toggleOption({ ...options.value[1] });\n        expect(localValue.value).toBe('b');\n      });\n\n      it('removes the value if option is already selected', () => {\n        localValue.value = 'b';\n\n        const {\n          toggleOption,\n        } = useSelectableOption(\n          options,\n          localValue,\n          noMultiple,\n        );\n\n        toggleOption({ ...options.value[1] });\n        expect(localValue.value).toBe(undefined);\n      });\n    });\n\n    describe('when working with multiple values', () => {\n      it('selects the option when localValue is some random value', () => {\n        localValue.value = 'b';\n        const {\n          toggleOption,\n        } = useSelectableOption(\n          options,\n          localValue,\n          multiple,\n        );\n\n        toggleOption({ ...options.value[1] });\n        expect(localValue.value).toEqual(['b']);\n      });\n\n      it('adds the option when localValue is empty array', () => {\n        localValue.value = [];\n\n        const {\n          toggleOption,\n        } = useSelectableOption(\n          options,\n          localValue,\n          multiple,\n        );\n\n        toggleOption({ ...options.value[1] });\n        expect(localValue.value).toEqual(['b']);\n      });\n\n      it('adds the option ', () => {\n        localValue.value = ['a'];\n\n        const {\n          toggleOption,\n        } = useSelectableOption(\n          options,\n          localValue,\n          multiple,\n        );\n\n        toggleOption({ ...options.value[1] });\n        expect(localValue.value).toEqual(['a', 'b']);\n      });\n\n      it('substracts the option if it is already selected', () => {\n        localValue.value = ['a', 'b', 'c'];\n        const {\n          toggleOption,\n        } = useSelectableOption(\n          options,\n          localValue,\n          multiple,\n        );\n\n        toggleOption({ ...options.value[1] });\n        expect(localValue.value).toEqual(['a', 'c']);\n      });\n    });\n  });\n\n  describe('optionIsSelected method', () => {\n    it('determines if a option is selected', () => {\n      const {\n        optionIsSelected,\n      } = useSelectableOption(\n        options,\n        localValue,\n        noMultiple,\n      );\n\n      localValue.value = 'a';\n\n      expect(optionIsSelected({ ...options.value[0] })).toBe(true);\n      expect(optionIsSelected({ ...options.value[1] })).toBe(false);\n    });\n\n    it('determines if a option is selected when working with multiple configuration', () => {\n      const {\n        optionIsSelected,\n      } = useSelectableOption(\n        options,\n        localValue,\n        multiple,\n      );\n\n      localValue.value = ['b'];\n\n      expect(optionIsSelected({ ...options.value[1] })).toBe(true);\n      expect(optionIsSelected({ ...options.value[0] })).toBe(false);\n    });\n\n    it('determines if a option is selected when working with multiple configuration and value is not an array', () => {\n      const {\n        optionIsSelected,\n      } = useSelectableOption(\n        options,\n        localValue,\n        multiple,\n      );\n\n      localValue.value = 'b';\n\n      expect(optionIsSelected({ ...options.value[1] })).toBe(false);\n      expect(optionIsSelected({ ...options.value[0] })).toBe(false);\n    });\n  });\n});\n"
  },
  {
    "path": "src/__tests/use/useSetup.ts",
    "content": "/* eslint-disable vue/one-component-per-file */\nimport {\n  defineComponent, createApp, h, ComponentPropsOptions,\n} from 'vue';\nimport { variantJS } from '../..';\nimport { VariantJSConfiguration } from '../../types';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype InstanceType<V> = V extends { new (...arg: any[]): infer X } ? X : never;\n\ntype VM<V> = InstanceType<V> & { unmount(): void };\n\nexport function mount<V>(Comp: V, attributes?: Record<string, unknown>, configuration?: VariantJSConfiguration): VM<V> {\n  const el = document.createElement('div');\n  const app = createApp(Comp, attributes);\n\n  app.use(variantJS, configuration);\n\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  return app.mount(el) as any as VM<V>;\n}\n\n// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types\nexport function useSetup<V>(\n  setup: () => V,\n  configuration?: VariantJSConfiguration,\n  attributes?: Record<string, unknown>,\n  props: ComponentPropsOptions = {},\n  componentName: keyof VariantJSConfiguration = 'TInput',\n) {\n  const componentOptions = {\n    name: componentName,\n    props,\n    setup,\n    render() {\n      return h('div', []);\n    },\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  } as any;\n\n  const Comp = defineComponent(componentOptions);\n\n  return mount(Comp, attributes, configuration);\n}\n"
  },
  {
    "path": "src/__tests/use/useVModel.spec.ts",
    "content": "import useVModel from '../../use/useVModel';\nimport { useSetup } from './useSetup';\n\ndescribe('useVModel', () => {\n  const defaultValue = 'default';\n\n  it('should work with default value', () => {\n    useSetup(() => {\n      const data = useVModel({\n        modelValue: defaultValue,\n      }, 'modelValue');\n      expect(data.value).toBe(defaultValue);\n    });\n  });\n\n  it('should work with a different value from the default', () => {\n    useSetup(() => {\n      const data = useVModel({\n        otherValue: defaultValue,\n      }, 'otherValue');\n      expect(data.value).toBe(defaultValue);\n    });\n  });\n});\n"
  },
  {
    "path": "src/__tests/utils/createDialogProgramatically.spec.ts",
    "content": "import { DialogIcon, DialogType } from '@variantjs/core';\nimport { VariantJSConfiguration } from '../..';\nimport createDialogProgramatically from '../../utils/createDialogProgramatically';\nimport TDialog from '@/components/TDialog.vue';\n\ndescribe('createDialogProgramatically', () => {\n  const configuration: VariantJSConfiguration = {};\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  let originalMounted: any;\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  let component: any;\n\n  beforeEach(() => {\n    originalMounted = TDialog.mounted;\n\n    // eslint-disable-next-line func-names\n    TDialog.mounted = function () {\n      component = this;\n    };\n  });\n\n  afterEach(() => {\n    TDialog.mounted = originalMounted;\n\n    component = undefined;\n  });\n\n  it('creates a dialog with a title, text and icon', () => {\n    const promise = createDialogProgramatically(\n      configuration,\n      DialogType.Alert,\n      'The title',\n      'The text',\n      DialogIcon.Error,\n    );\n\n    expect(promise).toBeInstanceOf(Promise);\n\n    expect(component.title).toEqual('The title');\n    expect(component.text).toEqual('The text');\n    expect(component.icon).toEqual(DialogIcon.Error);\n    expect(component.type).toEqual(DialogType.Alert);\n  });\n\n  it('creates a dialog with configuration', async () => {\n    const promise = createDialogProgramatically(\n      configuration,\n      DialogType.Alert,\n      {\n        title: 'The title',\n        text: 'The text',\n        icon: DialogIcon.Error,\n      },\n    );\n\n    expect(promise).toBeInstanceOf(Promise);\n\n    expect(component.title).toEqual('The title');\n    expect(component.text).toEqual('The text');\n    expect(component.icon).toEqual(DialogIcon.Error);\n    expect(component.type).toEqual(DialogType.Alert);\n  });\n\n  it('unmounts the dialog when promise resolved', async () => {\n    const unmountMock = jest.fn();\n    TDialog.unmounted = unmountMock;\n\n    createDialogProgramatically(\n      configuration,\n      DialogType.Alert,\n      {\n        title: 'The title',\n        text: 'The text',\n        icon: DialogIcon.Error,\n        focusOnOpen: false,\n        disableBodyScroll: false,\n      },\n    );\n\n    component.onUnmounted = unmountMock;\n\n    component.onBeforeHide({\n      cancel: () => null,\n      reason: 'other',\n    });\n\n    component.onHidden();\n\n    await component.$nextTick();\n\n    expect(unmountMock).toHaveBeenCalled();\n  });\n\n  it('unmounts the dialog when promise rejected', async () => {\n    const unmountMock = jest.fn();\n    TDialog.unmounted = unmountMock;\n\n    const promise = createDialogProgramatically(\n      configuration,\n      DialogType.Prompt,\n      {\n        title: 'The title',\n        text: 'The text',\n        icon: DialogIcon.Error,\n        focusOnOpen: false,\n        disableBodyScroll: false,\n      },\n    );\n\n    promise.catch(() => {\n      expect(true).toBe(true);\n    });\n\n    component.onUnmounted = unmountMock;\n\n    component.onBeforeHide({\n      cancel: () => null,\n      reason: 'cancel',\n    });\n\n    component.onHidden();\n\n    await component.$nextTick();\n    await component.$nextTick();\n\n    expect(unmountMock).toHaveBeenCalled();\n  });\n});\n"
  },
  {
    "path": "src/__tests/utils/emitter.spec.ts",
    "content": "import { Emitter } from '../../utils/emitter';\n\ndescribe('Emitter', () => {\n  let emitter: Emitter;\n\n  beforeEach(() => {\n    emitter = new Emitter();\n  });\n\n  it('calls the function every time when a registered event is called every', () => {\n    const eventFn = jest.fn();\n    emitter.on('event-name', eventFn);\n    expect(eventFn).not.toHaveBeenCalled();\n    emitter.emit('event-name');\n    expect(eventFn).toHaveBeenCalledTimes(1);\n    emitter.emit('event-name');\n    expect(eventFn).toHaveBeenCalledTimes(2);\n  });\n\n  it('calls the function only once on an event that is registered once', () => {\n    const eventFn = jest.fn();\n    emitter.once('event-name', eventFn);\n    expect(eventFn).not.toHaveBeenCalled();\n    emitter.emit('event-name');\n    emitter.emit('event-name');\n    expect(eventFn).toHaveBeenCalledTimes(1);\n  });\n\n  it('stops running a method when calling the off method', () => {\n    const eventFn = jest.fn();\n    const eventFn2 = jest.fn();\n    emitter.on('event-name', eventFn);\n    emitter.on('event-name', eventFn2);\n    emitter.emit('event-name');\n    expect(eventFn).toHaveBeenCalled();\n    expect(eventFn2).toHaveBeenCalled();\n    emitter.off('event-name', eventFn2);\n\n    emitter.emit('event-name');\n    expect(eventFn).toHaveBeenCalledTimes(2);\n    expect(eventFn2).toHaveBeenCalledTimes(1);\n  });\n\n  it('handles unexisting events when emitting', () => {\n    expect(() => {\n      emitter.emit('event-name');\n    }).not.toThrowError();\n  });\n\n  it('handles unexisting events when removing', () => {\n    expect(() => {\n      emitter.off('event-name', () => {});\n    }).not.toThrowError();\n  });\n\n  it('handles unexisting events methods when removing', () => {\n    expect(() => {\n      emitter.on('event-name', () => {});\n      emitter.off('event-name', () => {});\n    }).not.toThrowError();\n  });\n});\n"
  },
  {
    "path": "src/__tests/utils/getVariantProps.spec.ts",
    "content": "/* eslint-disable vue/one-component-per-file */\n\nimport { getVariantProps } from '../../utils/getVariantProps';\n\ndescribe('getVariantProps()', () => {\n  it('get the default variant props', () => {\n    const props = getVariantProps();\n    expect(props).toEqual({\n      classes: {\n        type: [String, Array, Object],\n        default: undefined,\n      },\n      fixedClasses: {\n        type: [String, Array, Object],\n        default: undefined,\n      },\n      variants: {\n        type: Object,\n        default: undefined,\n      },\n      variant: {\n        type: String,\n        default: undefined,\n      },\n    });\n  });\n});\n"
  },
  {
    "path": "src/__tests/utils/popper.spec.ts",
    "content": "/* eslint-disable @typescript-eslint/no-non-null-assertion */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { ModifierArguments } from '@popperjs/core';\nimport { Data } from '@variantjs/core';\nimport { sameWidthModifier } from '../../utils/popper';\n\ndescribe('sameWidthModifier', () => {\n  it('sets the popper width from the reference width', () => {\n    const options = {\n      state: {\n        styles: {\n          popper: {},\n        },\n        rects: {\n          reference: {\n            width: 100,\n          },\n        },\n      },\n\n    } as any as ModifierArguments<Data>;\n\n    sameWidthModifier.fn(options);\n\n    expect(options.state.styles.popper.width).toBe('100px');\n  });\n\n  it('sets the popper width from the reference width on `effect` function', () => {\n    const options = {\n      state: {\n        elements: {\n          popper: {\n            style: {},\n          },\n          reference: {\n            offsetWidth: 100,\n          },\n        },\n      },\n\n    } as any as ModifierArguments<Data>;\n\n    sameWidthModifier.effect!(options);\n\n    expect(options.state.elements.popper.style.width).toBe('100px');\n  });\n});\n"
  },
  {
    "path": "src/__tests/utils/svgToVueComponent.spec.ts",
    "content": "import { VNode } from 'vue';\nimport { svgToVueComponent } from '../../utils/svgToVueComponent';\n\ndescribe('svgToVueComponent', () => {\n  const svg = `<svg\n  xmlns=\"http://www.w3.org/2000/svg\"\n  fill=\"none\"\n  viewBox=\"0 0 24 24\"\n  stroke=\"currentColor\"\n><path\n  stroke-linecap=\"round\"\n  stroke-linejoin=\"round\"\n  stroke-width=\"2\"\n  d=\"M6 18L18 6M6 6l12 12\"\n/></svg>`;\n\n  it('should return a Vnode from an SVG string', () => {\n    const component: VNode = svgToVueComponent(svg);\n    expect(component.type).toBe('svg');\n\n    expect(svgToVueComponent(svg).type).toBe('svg');\n  });\n\n  it('handle html element values', () => {\n    const div = document.createElement('div');\n    div.innerHTML = 'Hello World';\n\n    const component: VNode = svgToVueComponent(div);\n\n    expect(component.type).toBe('DIV');\n  });\n\n  it('handles invalid element values', () => {\n    const component: VNode = svgToVueComponent('sfsd');\n\n    expect(component.type).toBe('span');\n  });\n});\n"
  },
  {
    "path": "src/assets/tailwind.css",
    "content": "@tailwind base;\n@tailwind components;\n@tailwind utilities;"
  },
  {
    "path": "src/components/TAlert.vue",
    "content": "<template>\n  <transitionable\n    :classes-list=\"configuration.classesList\"\n    :enabled=\"animate\"\n  >\n    <component\n      :is=\"tagName\"\n      v-if=\"shown\"\n      ref=\"wrapper\"\n      :class=\"configuration.classesList?.wrapper\"\n      v-bind=\"attributes\"\n    >\n      <component\n        :is=\"bodyTagName\"\n        ref=\"body\"\n        :class=\"configuration.classesList?.body\"\n      >\n        <slot\n          :show=\"doShow\"\n          :hide=\"doHide\"\n          :toggle=\"doToggle\"\n          :configuration=\"configuration\"\n        >\n          {{ configuration.text }}\n        </slot>\n      </component>\n\n      <slot\n        v-if=\"dismissible\"\n        name=\"closeButton\"\n        :show=\"doShow\"\n        :hide=\"doHide\"\n        :toggle=\"doToggle\"\n        :configuration=\"configuration\"\n      >\n        <button\n          ref=\"close\"\n          type=\"button\"\n          :class=\"configuration.classesList?.close\"\n          @click=\"doHide\"\n        >\n          <custom-icon\n            v-if=\"closeIcon\"\n            ref=\"closeIcon\"\n            :icon=\"closeIcon\"\n            :class=\"configuration.classesList?.closeIcon\"\n          />\n          <close-icon\n            v-else\n            ref=\"closeIcon\"\n          />\n        </button>\n      </slot>\n    </component>\n  </transitionable>\n</template>\n\n<script lang=\"ts\">\nimport {\n  TAlertConfig, TAlertClassesKeys, TAlertClassesValidKeys,\n} from '@variantjs/core';\nimport { defineComponent, PropType } from 'vue';\nimport { IconProp, TAlertOptions } from '../types';\nimport CustomIcon from '../icons/CustomIcon.vue';\nimport CloseIcon from '../icons/CloseIcon.vue';\nimport Transitionable from './misc/Transitionable.vue';\nimport useConfigurationWithClassesList from '../use/useConfigurationWithClassesList';\nimport { getVariantPropsWithClassesList } from '../utils/getVariantProps';\n\n// @vue/component\nexport default defineComponent({\n  name: 'TAlert',\n  compatConfig: {\n    MODE: 3,\n  },\n  components: {\n    CustomIcon,\n    CloseIcon,\n    Transitionable,\n  },\n  inheritAttrs: false,\n  props: {\n    ...getVariantPropsWithClassesList<TAlertOptions, TAlertClassesValidKeys>(),\n    text: {\n      type: String,\n      default: undefined,\n    },\n    tagName: {\n      type: String,\n      default: 'div',\n    },\n    bodyTagName: {\n      type: String,\n      default: 'div',\n    },\n    dismissible: {\n      type: Boolean,\n      default: true,\n    },\n    show: {\n      type: Boolean,\n      default: true,\n    },\n    timeout: {\n      type: Number,\n      default: undefined,\n    },\n    animate: {\n      type: Boolean,\n      default: true,\n    },\n    closeIcon: {\n      type: [Object, String] as PropType<IconProp>,\n      default: undefined,\n    },\n  },\n  emits: {\n    'update:show': (show: boolean) => typeof show === 'boolean',\n  },\n  setup() {\n    const { configuration, attributes } = useConfigurationWithClassesList<TAlertOptions>(TAlertConfig, TAlertClassesKeys);\n\n    return { configuration, attributes };\n  },\n  data({ configuration }) {\n    return {\n      shown: (configuration as unknown as TAlertOptions).show,\n      timer: null as ReturnType<typeof setTimeout> | null,\n    };\n  },\n  watch: {\n    shown(shown: boolean): void {\n      this.$emit('update:show', shown);\n    },\n    'configuration.show': function configurationShowWatch(show: boolean): void {\n      if (show) {\n        this.doShow();\n      } else {\n        this.doHide();\n      }\n    },\n  },\n  mounted() {\n    if (this.timeout) {\n      this.timer = setTimeout(() => this.doHide(), this.timeout);\n    }\n  },\n  unmounted() {\n    if (this.timer) {\n      clearTimeout(this.timer);\n    }\n  },\n  methods: {\n    doToggle(): void {\n      if (!this.shown) {\n        this.doShow();\n      } else {\n        this.doHide();\n      }\n    },\n    doShow(): void {\n      this.shown = true;\n    },\n    doHide(): void {\n      if (this.timer) {\n        clearTimeout(this.timer);\n        this.timer = null;\n      }\n\n      this.shown = false;\n    },\n  },\n});\n</script>\n"
  },
  {
    "path": "src/components/TButton.vue",
    "content": "<template>\n  <component\n    :is=\"routerLinkTag\"\n    v-if=\"useRouterLink\"\n    :to=\"configuration.to\"\n    :replace=\"configuration.replace\"\n    :active-class=\"configuration.activeClass\"\n    :exact-active-class=\"configuration.exactActiveClass\"\n    :custom=\"configuration.custom\"\n    :aria-current-value=\"configuration.ariaCurrentValue\"\n    v-bind=\"attributes\"\n  >\n    <slot />\n  </component>\n  <component\n    :is=\"guessedTagName\"\n    v-else\n    :href=\"configuration.href\"\n    v-bind=\"attributes\"\n  >\n    <slot />\n  </component>\n</template>\n\n<script lang=\"ts\">\nimport { TButtonConfig } from '@variantjs/core';\nimport { defineComponent, PropType } from 'vue';\nimport { TButtonOptions, VueRouteAriaCurrentValue, VueRouteRouteLocationRaw } from '../types';\nimport useConfiguration from '../use/useConfiguration';\nimport { getVariantProps } from '../utils/getVariantProps';\n\nexport default defineComponent({\n  name: 'TButton',\n  compatConfig: {\n    MODE: 3,\n  },\n  props: {\n    ...getVariantProps<TButtonOptions>(),\n    tagName: {\n      type: String,\n      default: 'button',\n      validator: (value: string): boolean => ['button', 'a'].indexOf(value) !== -1,\n    },\n    // Handled attributes\n    href: {\n      type: String,\n      default: undefined,\n    },\n    // RouterLink Props\n    to: {\n      type: [String, Object] as PropType<VueRouteRouteLocationRaw>,\n      default: undefined,\n    },\n    replace: {\n      type: Boolean,\n      default: false,\n    },\n    activeClass: {\n      type: String,\n      default: undefined,\n    },\n    exactActiveClass: {\n      type: String,\n      default: undefined,\n    },\n    custom: {\n      type: Boolean,\n      default: false,\n    },\n    ariaCurrentValue: {\n      type: String as PropType<VueRouteAriaCurrentValue>,\n      default: 'page',\n    },\n  },\n  setup() {\n    const { configuration, attributes } = useConfiguration<TButtonOptions>(TButtonConfig);\n\n    return { configuration, attributes };\n  },\n  computed: {\n    guessedTagName(): string {\n      if (this.configuration.href !== undefined) {\n        return 'a';\n      }\n\n      return this.tagName;\n    },\n    routerLinkComponentAvailable(): boolean {\n      return this.routerLinkTag !== null;\n    },\n    useRouterLink(): boolean {\n      return this.configuration.to !== undefined && this.routerLinkComponentAvailable;\n    },\n    routerLinkTag(): string | null {\n      const { components } = this.$.appContext;\n\n      if (components.RouterLink !== undefined) {\n        return 'RouterLink';\n      }\n\n      if (components.NuxtLink !== undefined) {\n        return 'NuxtLink';\n      }\n\n      return null;\n    },\n  },\n});\n</script>\n"
  },
  {
    "path": "src/components/TCard.vue",
    "content": "<template>\n  <component\n    :is=\"configuration.tagName\"\n    :class=\"configuration.classesList?.wrapper\"\n    v-bind=\"attributes\"\n  >\n    <div\n      v-if=\"$slots.header || configuration.header\"\n      ref=\"header\"\n      :class=\"configuration.classesList?.header\"\n    >\n      <slot\n        name=\"header\"\n        :configuration=\"configuration\"\n      >\n        {{ configuration.header }}\n      </slot>\n    </div>\n\n    <div\n      v-if=\"$slots.default || configuration.body\"\n      ref=\"body\"\n      :class=\"configuration.classesList?.body\"\n    >\n      <slot :configuration=\"configuration\">\n        {{ configuration.body }}\n      </slot>\n    </div>\n\n    <div\n      v-if=\"$slots.footer || configuration.footer\"\n      ref=\"footer\"\n      :class=\"configuration.classesList?.footer\"\n    >\n      <slot\n        name=\"footer\"\n        :configuration=\"configuration\"\n      >\n        {{ configuration.footer }}\n      </slot>\n    </div>\n  </component>\n</template>\n\n<script lang=\"ts\">\nimport { TCardConfig, TCardClassesKeys, TCardClassesValidKeys } from '@variantjs/core';\nimport { defineComponent } from 'vue';\nimport { TCardOptions } from '../types';\nimport useConfigurationWithClassesList from '../use/useConfigurationWithClassesList';\nimport { getVariantPropsWithClassesList } from '../utils/getVariantProps';\n\n// @vue/component\nexport default defineComponent({\n  name: 'TCard',\n  compatConfig: {\n    MODE: 3,\n  },\n  props: {\n    ...getVariantPropsWithClassesList<TCardOptions, TCardClassesValidKeys>(),\n    tagName: {\n      type: String,\n      default: 'div',\n    },\n    header: {\n      type: String,\n      default: undefined,\n    },\n    body: {\n      type: String,\n      default: undefined,\n    },\n    footer: {\n      type: String,\n      default: undefined,\n    },\n  },\n  setup() {\n    const { configuration, attributes } = useConfigurationWithClassesList<TCardOptions>(TCardConfig, TCardClassesKeys);\n\n    return { configuration, attributes };\n  },\n});\n\n</script>\n"
  },
  {
    "path": "src/components/TCheckbox.vue",
    "content": "<template>\n  <input\n    v-model=\"localValue\"\n    type=\"checkbox\"\n    v-bind=\"attributes\"\n  >\n</template>\n\n<script lang=\"ts\">\nimport { TCheckboxConfig } from '@variantjs/core';\nimport { defineComponent, PropType } from 'vue';\nimport { TCheckboxOptions, TCheckboxValue } from '../types';\nimport { getVariantProps } from '../utils/getVariantProps';\nimport useConfiguration from '../use/useConfiguration';\nimport useVModel from '../use/useVModel';\n\n// @vue/component\nexport default defineComponent({\n  name: 'TCheckbox',\n  compatConfig: {\n    MODE: 3,\n  },\n  props: {\n    ...getVariantProps<TCheckboxOptions>(),\n    modelValue: {\n      type: [String, Number, Boolean, Array, Object, Date, Function, Symbol] as PropType<TCheckboxValue>,\n      default: undefined,\n    },\n  },\n  setup(props) {\n    const localValue = useVModel(props, 'modelValue');\n\n    const { attributes } = useConfiguration<TCheckboxOptions>(TCheckboxConfig);\n\n    return {\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      localValue: localValue as any,\n      attributes,\n    };\n  },\n});\n\n</script>\n"
  },
  {
    "path": "src/components/TDialog.vue",
    "content": "<template>\n  <t-modal\n    ref=\"modalRef\"\n    v-model=\"showModel\"\n    :modal-attributes=\"configuration.dialogAttributes\"\n    :focus-on-open=\"false\"\n    :click-to-close=\"configuration.clickToClose\"\n    :esc-to-close=\"configuration.escToClose\"\n    :hide-close-button=\"! configuration.showCloseButton\"\n    :disable-body-scroll=\"configuration.disableBodyScroll\"\n    :body-scroll-lock-options=\"configuration.bodyScrollLockOptions\"\n    :teleport=\"configuration.teleport\"\n    :teleport-to=\"configuration.teleportTo\"\n    :classes=\"modalClasses\"\n    :fixed-classes=\"undefined\"\n    @shown=\"onShown\"\n    @hidden=\"onHidden\"\n    @before-show=\"onBeforeShow\"\n    @before-hide=\"onBeforeHide\"\n  >\n    <template #closeButton>\n      <button\n        v-if=\"!configuration.hideCloseButton\"\n        type=\"button\"\n        :disabled=\"busy\"\n        :class=\"configuration.classesList?.close\"\n        @click=\"hide(DialogHideReason.Close)\"\n      >\n        <slot\n          name=\"closeButtonIcon\"\n          :hide=\"hide\"\n        >\n          <close-icon :class=\"configuration.classesList?.closeIcon\" />\n        </slot>\n      </button>\n    </template>\n\n    <div\n      v-if=\"busy\"\n      :class=\"configuration.classesList?.busyWrapper\"\n    >\n      <loading-icon :class=\"configuration.classesList?.busyIcon\" />\n    </div>\n\n    <slot\n      :hide=\"hide\"\n      :ok=\"ok\"\n      :cancel=\"cancel\"\n    >\n      <div\n        v-if=\"errorMessage !== undefined\"\n        :class=\"configuration.classesList?.errorMessage\"\n      >\n        <slot\n          name=\"error\"\n          :setError=\"setError\"\n          :hide=\"hide\"\n          :error-message=\"errorMessage\"\n        >\n          {{ errorMessage }}\n        </slot>\n      </div>\n\n      <div\n        v-if=\"configuration.icon\"\n        ref=\"iconWrapperRef\"\n        :class=\"configuration.classesList?.iconWrapper\"\n      >\n        <slot\n          name=\"icon\"\n          :hide=\"hide\"\n          :ok=\"ok\"\n          :cancel=\"cancel\"\n        >\n          <template v-if=\"configuration.useSolidIcon\">\n            <solid-check-circle-icon\n              v-if=\"configuration.icon === 'success'\"\n              :class=\"configuration.classesList?.icon\"\n            />\n            <solid-question-mark-circle-icon\n              v-else-if=\"configuration.icon === 'question'\"\n              :class=\"configuration.classesList?.icon\"\n            />\n            <solid-information-circle-icon\n              v-else-if=\"configuration.icon === 'info'\"\n              :class=\"configuration.classesList?.icon\"\n            />\n            <solid-exclamation-icon\n              v-else-if=\"configuration.icon === 'warning'\"\n              :class=\"configuration.classesList?.icon\"\n            />\n            <solid-cross-circle-icon\n              v-else-if=\"configuration.icon === 'error'\"\n              :class=\"configuration.classesList?.icon\"\n            />\n          </template>\n          <template v-else>\n            <check-circle-icon\n              v-if=\"configuration.icon === 'success'\"\n              :class=\"configuration.classesList?.icon\"\n            />\n            <question-mark-circle-icon\n              v-else-if=\"configuration.icon === 'question'\"\n              :class=\"configuration.classesList?.icon\"\n            />\n            <information-circle-icon\n              v-else-if=\"configuration.icon === 'info'\"\n              :class=\"configuration.classesList?.icon\"\n            />\n            <exclamation-icon\n              v-else-if=\"configuration.icon === 'warning'\"\n              :class=\"configuration.classesList?.icon\"\n            />\n            <cross-circle-icon\n              v-else-if=\"configuration.icon === 'error'\"\n              :class=\"configuration.classesList?.icon\"\n            />\n          </template>\n        </slot>\n      </div>\n\n      <div :class=\"configuration.classesList?.content\">\n        <div\n          v-if=\"configuration.title !== undefined || $slots.title\"\n          :class=\"configuration.classesList?.titleWrapper\"\n        >\n          <component\n            :is=\"configuration.titleTag\"\n\n            :class=\"configuration.classesList?.title\"\n          >\n            <slot\n              name=\"title\"\n              :hide=\"hide\"\n              :ok=\"ok\"\n              :cancel=\"cancel\"\n            >\n              {{ configuration.title }}\n            </slot>\n          </component>\n        </div>\n        <div\n          v-if=\"configuration.text !== undefined || $slots.text\"\n          :class=\"configuration.classesList?.textWrapper\"\n        >\n          <component\n            :is=\"configuration.textTag\"\n            :class=\"configuration.classesList?.text\"\n          >\n            <slot\n              name=\"text\"\n              :hide=\"hide\"\n              :ok=\"ok\"\n              :cancel=\"cancel\"\n            >\n              {{ configuration.text }}\n            </slot>\n          </component>\n        </div>\n\n        <template v-if=\"configuration.type === 'prompt'\">\n          <div\n            ref=\"inputWrapperRef\"\n            :class=\"configuration.classesList?.inputWrapper\"\n          >\n            <slot\n              name=\"input\"\n              :hide=\"hide\"\n              :ok=\"ok\"\n              :cancel=\"cancel\"\n              :setInputValue=\"setInputValue\"\n              :inputValue=\"inputValue\"\n              :variant=\"configuration.inputVariant\"\n              :inputAttributes=\"configuration.inputAttributes\"\n            >\n              <input\n                v-model=\"inputModel\"\n                :variant=\"configuration.inputVariant\"\n                :type=\"configuration.inputType\"\n                :class=\"configuration.classesList?.input\"\n                v-bind=\"configuration.inputAttributes\"\n              >\n            </slot>\n\n            <div\n              v-if=\"validationErrorMessage !== undefined\"\n              :class=\"configuration.classesList?.inputValidationError\"\n            >\n              <slot\n                name=\"validation-error\"\n                :setError=\"setValidationError\"\n                :hide=\"hide\"\n                :error-message=\"validationErrorMessage\"\n              >\n                {{ validationErrorMessage }}\n              </slot>\n            </div>\n          </div>\n        </template>\n      </div>\n    </slot>\n\n    <template #footer>\n      <slot\n        name=\"footer\"\n        :hide=\"hide\"\n        :ok=\"ok\"\n        :cancel=\"cancel\"\n      >\n        <button\n          v-if=\"showCancelButton\"\n          ref=\"cancelButton\"\n          type=\"button\"\n          :class=\"configuration.classesList?.cancelButton\"\n          :aria-label=\"cancelButtonAriaLabel\"\n          :disabled=\"busy\"\n          @click=\"cancel\"\n        >\n          {{ cancelButtonText }}\n        </button>\n        <button\n          ref=\"okButton\"\n          type=\"button\"\n          :class=\"configuration.classesList?.okButton\"\n          :aria-label=\"okButtonAriaLabel\"\n          :disabled=\"busy\"\n          @click=\"ok\"\n        >\n          {{ okButtonText }}\n        </button>\n      </slot>\n    </template>\n  </t-modal>\n</template>\n\n<script lang=\"ts\">\nimport {\n  defineComponent, PropType, HTMLAttributes, inject, computed, ref, onMounted, watch,\n} from 'vue';\nimport { BodyScrollOptions } from 'body-scroll-lock';\nimport {\n  Data,\n  TDialogClassesKeys,\n  TDialogClassesValidKeys,\n  DialogType,\n  DialogPreconfirmFn,\n  DialogResponse,\n  DialogHideReason,\n  DialogInputValidatorFn,\n  TDialogConfig,\n  ModalHideReason,\n  getFocusableElements,\n  promisifyFunctionResult,\n  DialogBeforeHideParams,\n  DialogBeforeShowParams,\n} from '@variantjs/core';\nimport {\n  TDialogOptions, EmitterInterface, PromiseRejectFn,\n} from '../types';\nimport useConfigurationWithClassesList from '../use/useConfigurationWithClassesList';\nimport { getVariantPropsWithClassesList } from '../utils/getVariantProps';\nimport useVModel from '../use/useVModel';\nimport TModal from './TModal.vue';\nimport CheckCircleIcon from '../icons/CheckCircleIcon.vue';\nimport QuestionMarkCircleIcon from '../icons/QuestionMarkCircleIcon.vue';\nimport InformationCircleIcon from '../icons/InformationCircleIcon.vue';\nimport ExclamationIcon from '../icons/ExclamationIcon.vue';\nimport SolidCheckCircleIcon from '../icons/SolidCheckCircleIcon.vue';\nimport SolidQuestionMarkCircleIcon from '../icons/SolidQuestionMarkCircleIcon.vue';\nimport SolidInformationCircleIcon from '../icons/SolidInformationCircleIcon.vue';\nimport SolidExclamationIcon from '../icons/SolidExclamationIcon.vue';\nimport CrossCircleIcon from '../icons/CrossCircleIcon.vue';\nimport SolidCrossCircleIcon from '../icons/SolidCrossCircleIcon.vue';\nimport LoadingIcon from '../icons/LoadingIcon.vue';\nimport CloseIcon from '../icons/CloseIcon.vue';\n\n// @vue/component\nexport default defineComponent({\n  name: 'TDialog',\n  compatConfig: {\n    MODE: 3,\n  },\n  components: {\n    TModal,\n    CloseIcon,\n    LoadingIcon,\n    CrossCircleIcon,\n    SolidCrossCircleIcon,\n    CheckCircleIcon,\n    QuestionMarkCircleIcon,\n    InformationCircleIcon,\n    ExclamationIcon,\n    SolidQuestionMarkCircleIcon,\n    SolidInformationCircleIcon,\n    SolidExclamationIcon,\n    SolidCheckCircleIcon,\n  },\n  props: {\n    ...getVariantPropsWithClassesList<TDialogOptions, TDialogClassesValidKeys>(),\n    type: {\n      type: String,\n      default: DialogType.Alert,\n    },\n    icon: {\n      type: String,\n      default: undefined,\n    },\n    useSolidIcon: {\n      type: Boolean,\n      default: false,\n    },\n    rejectOnCancel: {\n      type: Boolean,\n      default: true,\n    },\n    rejectOnDismiss: {\n      type: Boolean,\n      default: undefined,\n    },\n    title: {\n      type: String,\n      default: undefined,\n    },\n    titleTag: {\n      type: String,\n      default: 'h3',\n    },\n    textTag: {\n      type: String,\n      default: 'p',\n    },\n    text: {\n      type: String,\n      default: undefined,\n    },\n    cancelButtonText: {\n      type: String,\n      default: 'Cancel',\n    },\n    cancelButtonAriaLabel: {\n      type: String,\n      default: 'Cancel',\n    },\n    okButtonText: {\n      type: String,\n      default: 'OK',\n    },\n    okButtonAriaLabel: {\n      type: String,\n      default: 'OK',\n    },\n    preConfirm: {\n      type: Function as PropType<DialogPreconfirmFn>,\n      default: undefined,\n    },\n    name: {\n      type: String,\n      default: undefined,\n    },\n    modelValue: {\n      type: Boolean,\n      default: false,\n    },\n    dialogAttributes: {\n      type: Object as PropType<HTMLAttributes & Data>,\n      default: () => ({}),\n    },\n    focusOnOpen: {\n      type: Boolean,\n      default: true,\n    },\n    clickToClose: {\n      type: Boolean,\n      default: true,\n    },\n    escToClose: {\n      type: Boolean,\n      default: true,\n    },\n    showCloseButton: {\n      type: Boolean,\n      default: true,\n    },\n    disableBodyScroll: {\n      type: Boolean,\n      default: true,\n    },\n    bodyScrollLockOptions: {\n      type: Object as PropType<BodyScrollOptions>,\n      default: () => ({}),\n    },\n    teleport: {\n      type: Boolean,\n      default: true,\n    },\n    teleportTo: {\n      type: [String, Object] as PropType<string | HTMLElement>,\n      default: 'body',\n    },\n    inputAttributes: {\n      type: Object as PropType<HTMLAttributes & Data>,\n      default: () => ({}),\n    },\n    inputType: {\n      type: String,\n      default: 'text',\n    },\n    inputValidator: {\n      type: Function as PropType<DialogInputValidatorFn>,\n      default: undefined,\n    },\n    inputValue: {\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      type: [String, Number, Boolean, Array, Object, Date, Function, Symbol],\n      default: undefined,\n    },\n  },\n  emits: {\n    shown: () => true,\n    // eslint-disable-next-line @typescript-eslint/no-unused-vars\n    hidden: (response: DialogResponse) => true,\n    // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any\n    error: (response: any) => true,\n    // eslint-disable-next-line @typescript-eslint/no-unused-vars\n    'validation-error': (message: string) => true,\n    // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any\n    'before-show': (e: DialogBeforeShowParams) => true,\n    // eslint-disable-next-line @typescript-eslint/no-unused-vars\n    'before-hide': (e: DialogBeforeHideParams) => true,\n    'update:modelValue': () => true,\n  },\n  setup(props, { emit }) {\n    const { configuration, attributes } = useConfigurationWithClassesList<TDialogOptions>(TDialogConfig, TDialogClassesKeys);\n\n    const inputWrapperRef = ref<HTMLDivElement>();\n\n    const modalRef = ref<typeof TModal>();\n\n    const showModel = useVModel(props, 'modelValue');\n\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    const inputModel = ref<any>(props.inputValue);\n\n    const busy = ref<boolean>(false);\n\n    const errorMessage = ref<string | undefined>(undefined);\n\n    const validationErrorMessage = ref<string | undefined>(undefined);\n\n    const hideReason = ref<DialogHideReason | undefined>(undefined);\n\n    const dialogResponse = ref<DialogResponse | undefined>(undefined);\n\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    const preConfirmResponse = ref<any>(undefined);\n\n    const promiseResolve = ref<((value: DialogResponse) => void) | undefined>(undefined);\n\n    const promiseReject = ref<PromiseRejectFn | undefined>(undefined);\n\n    const isPrompt = computed<boolean>(() => configuration.type === DialogType.Prompt);\n\n    const setError = (error: string | undefined | Error) => {\n      if (error instanceof Error) {\n        errorMessage.value = error.message;\n      } else {\n        errorMessage.value = error;\n      }\n    };\n\n    const setValidationError = (error: string | undefined) => {\n      validationErrorMessage.value = error;\n    };\n\n    const focusDialog = () => {\n      modalRef.value!.focusModal();\n    };\n\n    const focusPromptInput = () => {\n      const focusableField = getFocusableElements(inputWrapperRef.value!).shift();\n      if (focusableField) {\n        focusableField.focus();\n      } else {\n        focusDialog();\n      }\n    };\n\n    const initDialog = () => {\n      if (configuration.focusOnOpen) {\n        if (isPrompt.value) {\n          focusPromptInput();\n        } else {\n          focusDialog();\n        }\n      }\n    };\n\n    onMounted(() => {\n      if (showModel.value) {\n        initDialog();\n      }\n    });\n\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    const setInputValue = (value: any) => {\n      inputModel.value = value;\n    };\n\n    const reset = (): void => {\n      promiseResolve.value = undefined;\n      promiseReject.value = undefined;\n      hideReason.value = undefined;\n      dialogResponse.value = undefined;\n      busy.value = false;\n      setError(undefined);\n      setValidationError(undefined);\n      preConfirmResponse.value = undefined;\n      setInputValue(props.inputValue);\n    };\n\n    const onBeforeShow = (e: DialogBeforeShowParams) => {\n      emit('before-show', e);\n    };\n\n    const onBeforeHide = (e: { cancel: PromiseRejectFn, reason: ModalHideReason }) => {\n      // The `e.reason` comes from the modal so may differ to the dialog reason\n      const hideReasonValue: DialogHideReason = (hideReason.value !== undefined ? hideReason.value : e.reason) as DialogHideReason;\n\n      if (busy.value && hideReasonValue !== DialogHideReason.Ok) {\n        e.cancel();\n        return;\n      }\n\n      const response: DialogResponse = {\n        hideReason: hideReasonValue,\n        isOk: hideReasonValue === DialogHideReason.Ok,\n        isCancel: hideReasonValue === DialogHideReason.Cancel,\n        isDismissed: ![DialogHideReason.Cancel, DialogHideReason.Ok].includes(hideReasonValue),\n      };\n\n      if (configuration.preConfirm) {\n        response.response = preConfirmResponse.value;\n      }\n\n      if (isPrompt.value) {\n        response.input = inputModel.value;\n      }\n\n      dialogResponse.value = response;\n\n      emit('before-hide', {\n        cancel: e.cancel,\n        response,\n      });\n    };\n\n    const rejectOnDismiss = computed<boolean>(() => {\n      if (configuration.rejectOnDismiss === undefined) {\n        return configuration.type !== DialogType.Alert;\n      }\n\n      return configuration.rejectOnDismiss;\n    });\n\n    const onHidden = () => {\n      const response = dialogResponse.value!;\n\n      emit('hidden', response);\n\n      if (\n        (response.isCancel && configuration.rejectOnCancel)\n        || (response.isDismissed && rejectOnDismiss.value)\n      ) {\n        if (promiseReject.value) {\n          promiseReject.value(response);\n        }\n      } else if (promiseResolve.value) {\n        promiseResolve.value(response);\n      }\n\n      reset();\n    };\n\n    const onShown = () => {\n      emit('shown');\n\n      initDialog();\n    };\n\n    const hide = (reason: DialogHideReason = DialogHideReason.Other) :void => {\n      hideReason.value = reason;\n\n      showModel.value = false;\n    };\n\n    const ok = () : void => {\n      setValidationError(undefined);\n\n      setError(undefined);\n\n      if (configuration.inputValidator && isPrompt.value) {\n        const response = configuration.inputValidator(inputModel.value);\n\n        if (typeof response === 'string' && response.length > 0) {\n          setValidationError(response);\n\n          emit('validation-error', response);\n\n          return;\n        }\n      }\n\n      if (configuration.preConfirm) {\n        const promise = promisifyFunctionResult(configuration.preConfirm, inputModel.value);\n\n        busy.value = true;\n\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\n        promise.then((response: any) => {\n          preConfirmResponse.value = response;\n\n          hide(DialogHideReason.Ok);\n        }).catch((error) => {\n          setError(error);\n\n          emit('error', error);\n        }).then(() => {\n          busy.value = false;\n        });\n      } else {\n        hide(DialogHideReason.Ok);\n      }\n    };\n\n    const cancel = () :void => {\n      hide(DialogHideReason.Cancel);\n    };\n\n    const show = () : Promise<DialogResponse> => {\n      const promise = new Promise((resolve, reject) => {\n        promiseResolve.value = resolve;\n\n        promiseReject.value = reject;\n\n        showModel.value = true;\n      });\n\n      // eslint-disable-next-line consistent-return\n      return promise as Promise<DialogResponse>;\n    };\n\n    if (configuration.name) {\n      const emitter = inject<EmitterInterface>('emitter')!;\n\n      emitter.on('dialog:show', (name: string, resolve: ((value: DialogResponse) => void), reject: PromiseRejectFn) => {\n        if (configuration.name !== name) {\n          return;\n        }\n\n        promiseResolve.value = resolve;\n\n        promiseReject.value = reject;\n\n        showModel.value = true;\n      });\n\n      emitter.on('dialog:hide', (name) => {\n        if (configuration.name !== name) {\n          return;\n        }\n\n        hide(DialogHideReason.Method);\n      });\n    }\n\n    watch(inputModel, () => {\n      if (!configuration.inputValidator) {\n        return;\n      }\n\n      const response = configuration.inputValidator(inputModel.value);\n\n      if (typeof response === 'string' && response.length > 0) {\n        setValidationError(response);\n\n        emit('validation-error', response);\n      } else {\n        setValidationError(undefined);\n      }\n    });\n\n    const modalClasses = computed(() => ({\n      overlay: configuration.classesList!.overlay,\n      wrapper: configuration.classesList!.wrapper,\n      modal: configuration.classesList!.dialog,\n      body: configuration.classesList!.body,\n      footer: configuration.classesList!.buttons,\n      overlayEnterActiveClass: configuration.classesList!.overlayEnterActiveClass,\n      overlayEnterFromClass: configuration.classesList!.overlayEnterFromClass,\n      overlayEnterToClass: configuration.classesList!.overlayEnterToClass,\n      overlayLeaveActiveClass: configuration.classesList!.overlayLeaveActiveClass,\n      overlayLeaveFromClass: configuration.classesList!.overlayLeaveFromClass,\n      overlayLeaveToClass: configuration.classesList!.overlayLeaveToClass,\n      enterActiveClass: configuration.classesList!.enterActiveClass,\n      enterFromClass: configuration.classesList!.enterFromClass,\n      enterToClass: configuration.classesList!.enterToClass,\n      leaveActiveClass: configuration.classesList!.leaveActiveClass,\n      leaveFromClass: configuration.classesList!.leaveFromClass,\n      leaveToClass: configuration.classesList!.leaveToClass,\n    }));\n\n    const showCancelButton = computed(() => configuration.type !== DialogType.Alert);\n\n    return {\n      configuration,\n      attributes,\n      showModel,\n      modalClasses,\n      showCancelButton,\n      DialogHideReason,\n      inputModel,\n      busy,\n      show,\n      hide,\n      ok,\n      cancel,\n      onBeforeShow,\n      onBeforeHide,\n      onShown,\n      onHidden,\n      setInputValue,\n      setError,\n      setValidationError,\n      errorMessage,\n      validationErrorMessage,\n      inputWrapperRef,\n      modalRef,\n\n    };\n  },\n});\n</script>\n"
  },
  {
    "path": "src/components/TDropdown.vue",
    "content": "<template>\n  <component\n    :is=\"tagName\"\n    ref=\"trigger\"\n    :type=\"tagName === 'button' ? 'button' : undefined\"\n    :aria-expanded=\"shown\"\n    :class=\"configuration.classesList?.trigger\"\n    :disabled=\"configuration.disabled\"\n    v-bind=\"{...attributes, ...$attrs}\"\n    @click=\"clickHandler\"\n    @focus=\"focusHandler\"\n    @blur=\"blurHandler\"\n    @mouseover=\"mouseoverHandler\"\n    @mouseleave=\"mouseleaveHandler\"\n  >\n    <slot\n      :configuration=\"configuration\"\n      :is-show=\"shown\"\n      :popper=\"popper\"\n      name=\"trigger\"\n    >\n      {{ configuration.text }}\n    </slot>\n  </component>\n\n  <teleport\n    :to=\"configuration.teleportTo\"\n    :disabled=\"! configuration.teleport\"\n  >\n    <transitionable\n      :enabled=\"popperIsAdjusted || !initAsShow\"\n      :classes-list=\"configuration.classesList\"\n      @after-leave=\"dropdownAfterLeave\"\n    >\n      <component\n        :is=\"dropdownTagName\"\n        v-show=\"shown || adjustingPopper || initAsShow\"\n        ref=\"dropdown\"\n        :style=\"adjustingPopper ? 'opacity:0' : undefined\"\n        :class=\"configuration.classesList?.dropdown\"\n        :aria-hidden=\"!shown\"\n        tabindex=\"-1\"\n        v-bind=\"dropdownAttributes\"\n        @blur=\"blurHandler\"\n        @mouseover=\"mouseoverHandler\"\n        @mouseleave=\"mouseleaveHandler\"\n      >\n        <slot\n          :show=\"doShow\"\n          :hide=\"doHide\"\n          :toggle=\"doToggle\"\n          :configuration=\"configuration\"\n          :popper=\"popper\"\n        />\n      </component>\n    </transitionable>\n  </teleport>\n</template>\n\n<script lang=\"ts\">\nimport {\n  createPopper, Instance as PopperInstance, Options, Placement,\n} from '@popperjs/core';\nimport {\n  TDropdownConfig,\n  TDropdownClassesKeys,\n  TDropdownClassesValidKeys,\n  debounce,\n  elementIsTargetOrTargetChild,\n  getFocusableElements,\n  isTouchOnlyDevice as getIsTouch,\n  throttle,\n  TDropdownPopperDefaultOptions as defaultPopperOptions,\n  DebouncedFn,\n} from '@variantjs/core';\nimport {\n  defineComponent, PropType, onMounted, ref,\n} from 'vue';\nimport { TDropdownOptions } from '../types';\nimport useConfigurationWithClassesList from '../use/useConfigurationWithClassesList';\nimport { getVariantPropsWithClassesList } from '../utils/getVariantProps';\nimport Transitionable from './misc/Transitionable.vue';\n\nexport const validDropdownPlacements = [\n  'auto',\n  'auto-start',\n  'auto-end',\n  'top',\n  'top-start',\n  'top-end',\n  'bottom',\n  'bottom-start',\n  'bottom-end',\n  'right',\n  'right-start',\n  'right-end',\n  'left',\n  'left-start',\n  'left-end',\n];\n\n// @vue/component\nexport default defineComponent({\n  name: 'TDropdown',\n  compatConfig: {\n    MODE: 3,\n  },\n  components: { Transitionable },\n  inheritAttrs: false,\n  props: {\n    ...getVariantPropsWithClassesList<TDropdownOptions, TDropdownClassesValidKeys>(),\n    text: {\n      type: String,\n      default: undefined,\n    },\n    teleport: {\n      type: Boolean,\n      default: false,\n    },\n    teleportTo: {\n      type: [String, Object] as PropType<string | HTMLElement>,\n      default: 'body',\n    },\n    tagName: {\n      type: String,\n      default: 'button',\n    },\n    dropdownTagName: {\n      type: String,\n      default: 'div',\n    },\n    dropdownAttributes: {\n      type: Object,\n      default: undefined,\n    },\n    disabled: {\n      type: Boolean,\n      default: undefined,\n    },\n    toggleOnFocus: {\n      type: Boolean,\n      default: true,\n    },\n    toggleOnClick: {\n      type: Boolean,\n      default: true,\n    },\n    toggleOnHover: {\n      type: Boolean,\n      default: false,\n    },\n    hideOnLeaveTimeout: {\n      type: Number,\n      default: 250,\n    },\n    show: {\n      type: Boolean,\n      default: false,\n    },\n    placement: {\n      type: String as PropType<Placement>,\n      default: undefined,\n      validator: (value: Placement | string):boolean => validDropdownPlacements.includes(value),\n    },\n    popperOptions: {\n      type: Object as PropType<Options>,\n      default: (): Options => defaultPopperOptions as Options,\n    },\n  },\n  emits: {\n    'update:show': (show: boolean) => typeof show === 'boolean',\n    focus: (e: FocusEvent) => e instanceof FocusEvent,\n    blur: (e: FocusEvent) => e instanceof FocusEvent,\n    'blur-on-child': (e: FocusEvent) => e instanceof FocusEvent,\n    click: (e: MouseEvent) => e instanceof MouseEvent,\n    mouseover: (e: MouseEvent) => e instanceof MouseEvent,\n    mouseleave: (e: MouseEvent) => e instanceof MouseEvent,\n    touchstart: (e: TouchEvent) => e instanceof TouchEvent,\n    shown: () => true,\n    hidden: () => true,\n    'before-show': () => true,\n    'before-hide': () => true,\n  },\n  setup() {\n    const { configuration, attributes } = useConfigurationWithClassesList<TDropdownOptions>(TDropdownConfig, TDropdownClassesKeys);\n\n    const isTouchOnlyDevice = ref<boolean>(false);\n\n    onMounted(() => {\n      isTouchOnlyDevice.value = getIsTouch();\n    });\n\n    return { configuration, attributes, isTouchOnlyDevice };\n  },\n  data({ configuration }) {\n    return {\n      shown: (configuration as unknown as TDropdownOptions).show,\n      // Disables the animation while the dropdown is being shown\n      initAsShow: (configuration as unknown as TDropdownOptions).show,\n      hideTimeout: null as ReturnType<typeof setTimeout> | null,\n      focusableElements: [] as Array<HTMLElement>,\n      throttledToggle: null as null | (() => void),\n      adjustingPopper: false,\n      popperIsAdjusted: false,\n      popperAdjusterListener: null as null | DebouncedFn,\n      popper: null as PopperInstance | null,\n    };\n  },\n  computed: {\n    fullPopperOptions(): Options {\n      const popperOptions = this.configuration.popperOptions as Options;\n\n      if (this.configuration.placement !== undefined) {\n        popperOptions.placement = this.configuration.placement;\n      }\n\n      return popperOptions;\n    },\n    shouldShowWhenClicked(): boolean {\n      return this.isTouchOnlyDevice\n        && (this.configuration.toggleOnFocus === true || this.configuration.toggleOnHover === true);\n    },\n  },\n  watch: {\n    popperIsAdjusted(popperIsAdjusted: boolean): void {\n      if (popperIsAdjusted) {\n        this.enablePopperNeedsAdjustmentListener();\n      } else {\n        this.disablePopperNeedsAdjustmentListener();\n      }\n    },\n    'configuration.show': function configurationShowWatch(show: boolean): void {\n      if (show) {\n        this.doShow();\n      } else {\n        this.doHide();\n      }\n    },\n  },\n  mounted() {\n    if (this.isTouchOnlyDevice && this.shown) {\n      window.addEventListener('touchstart', this.touchstartHandler);\n    }\n\n    if (this.configuration.show) {\n      this.updatePopper().then(() => {\n        this.initAsShow = false;\n      });\n    }\n  },\n  created() {\n    this.throttledToggle = throttle(this.doToggle, 200);\n\n    this.popperAdjusterListener = debounce(() => {\n      this.popperIsAdjusted = false;\n    }, 200);\n  },\n  beforeUnmount() {\n    if (this.hideTimeout) {\n      clearTimeout(this.hideTimeout);\n    }\n\n    this.disablePopperNeedsAdjustmentListener();\n\n    if (this.isTouchOnlyDevice && this.shown) {\n      window.removeEventListener('touchstart', this.touchstartHandler);\n    }\n  },\n  methods: {\n    focus(): void {\n      this.getTriggerElement().focus();\n    },\n    onShown(): void {\n      this.$emit('shown');\n\n      this.$emit('update:show', true);\n\n      if (this.isTouchOnlyDevice) {\n        window.addEventListener('touchstart', this.touchstartHandler);\n      } else {\n        this.addBlurListenersToChildElements();\n      }\n    },\n    onHidden(): void {\n      this.$emit('hidden');\n\n      this.$emit('update:show', false);\n\n      if (this.isTouchOnlyDevice) {\n        window.removeEventListener('touchstart', this.touchstartHandler);\n      } else {\n        this.removeBlurListenersFromChildElements();\n      }\n    },\n    onBeforeShown(): void {\n      this.$emit('before-show');\n      if (this.isTouchOnlyDevice) {\n        window.addEventListener('touchstart', this.touchstartHandler);\n      }\n    },\n    onBeforeHide(): void {\n      this.$emit('before-hide');\n      if (this.isTouchOnlyDevice) {\n        window.removeEventListener('touchstart', this.touchstartHandler);\n      }\n    },\n    addBlurListenersToChildElements(): void {\n      const dropdown = this.getDropdownElement();\n\n      this.focusableElements = getFocusableElements(dropdown);\n      this.focusableElements.forEach((element) => element.addEventListener('blur', this.blurHandler));\n    },\n    removeBlurListenersFromChildElements(): void {\n      this.focusableElements.forEach((element) => element.removeEventListener('blur', this.blurHandler));\n      this.focusableElements = [];\n    },\n    dropdownAfterLeave(): void {\n      this.getDropdownElement().style.removeProperty('visibility');\n    },\n    async adjustPopper(): Promise<void> {\n      // eslint-disable-next-line no-async-promise-executor\n      return new Promise(async (resolve) => {\n        if (this.shown === false && this.adjustingPopper === false) {\n          this.popperIsAdjusted = false;\n          resolve();\n          return;\n        }\n\n        if (!this.popper) {\n          this.popper = await this.createPopper();\n        }\n\n        await this.popper.update();\n\n        resolve();\n      });\n    },\n    updatePopper(): Promise<void> {\n      // eslint-disable-next-line no-async-promise-executor\n      return new Promise(async (resolve) => {\n        if (this.popperIsAdjusted) {\n          resolve();\n          return;\n        }\n\n        // So it appears in the DOM so it can be adjusted\n        this.adjustingPopper = true;\n\n        await this.$nextTick();\n\n        await this.adjustPopper();\n\n        // after adjusted it removes the dropdown from the DOM\n        this.adjustingPopper = false;\n\n        await this.$nextTick();\n\n        // Once removed it can be marked as adjusted so we can enable the\n        // CSS transitions\n        this.popperIsAdjusted = true;\n\n        await this.$nextTick();\n\n        resolve();\n      });\n    },\n    createPopper(): Promise<PopperInstance> {\n      let popper: PopperInstance;\n\n      return new Promise((resolve) => {\n        const popperOptions = this.fullPopperOptions;\n\n        const originalOnFirstUpdate = popperOptions.onFirstUpdate;\n\n        popperOptions.onFirstUpdate = async (arg) => {\n          if (originalOnFirstUpdate) {\n            originalOnFirstUpdate(arg);\n          }\n\n          resolve(popper);\n        };\n\n        popper = createPopper(this.getTriggerElement(), this.getDropdownElement(), this.fullPopperOptions);\n      });\n    },\n    enablePopperNeedsAdjustmentListener() : void {\n      window.addEventListener('resize', this.popperAdjusterListener!);\n\n      window.addEventListener('scroll', this.popperAdjusterListener!);\n    },\n    disablePopperNeedsAdjustmentListener() : void {\n      window.removeEventListener('resize', this.popperAdjusterListener!);\n\n      window.removeEventListener('scroll', this.popperAdjusterListener!);\n\n      this.popperAdjusterListener!.cancel();\n    },\n    getDropdownElement(): HTMLDivElement {\n      const { dropdown } = this.$refs;\n      return dropdown as HTMLDivElement;\n    },\n    getTriggerElement(): HTMLButtonElement {\n      const { trigger } = this.$refs;\n      return trigger as HTMLButtonElement;\n    },\n    doToggle(): void {\n      if (!this.shown) {\n        this.doShow();\n      } else {\n        this.doHide();\n      }\n    },\n    async doShow(): Promise<void> {\n      if (this.hideTimeout) {\n        clearTimeout(this.hideTimeout);\n      }\n\n      this.onBeforeShown();\n\n      await this.updatePopper();\n\n      this.shown = true;\n\n      await this.$nextTick();\n\n      this.onShown();\n    },\n    async doHide(): Promise<void> {\n      this.onBeforeHide();\n\n      this.shown = false;\n\n      await this.$nextTick();\n\n      this.onHidden();\n    },\n    clickHandler(e: MouseEvent): void {\n      this.$emit('click', e);\n\n      if (this.configuration.toggleOnClick) {\n        this.throttledToggle!();\n      } else if (this.shouldShowWhenClicked) {\n        this.doShow();\n      }\n    },\n    focusHandler(e: FocusEvent): void {\n      this.$emit('focus', e);\n\n      if (this.isTouchOnlyDevice) {\n        return;\n      }\n\n      if (this.configuration.toggleOnFocus) {\n        this.throttledToggle!();\n      }\n    },\n    blurHandler(e: FocusEvent): void {\n      const isChild = this.targetIsChild(e.relatedTarget);\n\n      if (!isChild) {\n        this.$emit('blur', e);\n      } else {\n        this.$emit('blur-on-child', e);\n      }\n\n      if (this.isTouchOnlyDevice) {\n        return;\n      }\n\n      if (this.configuration.toggleOnFocus && !isChild) {\n        this.doHide();\n      }\n    },\n    targetIsChild(target: EventTarget | null): boolean {\n      return elementIsTargetOrTargetChild(target, this.getDropdownElement())\n        || elementIsTargetOrTargetChild(target, this.getTriggerElement());\n    },\n    mouseoverHandler(e: MouseEvent): void {\n      this.$emit('mouseover', e);\n\n      if (this.isTouchOnlyDevice) {\n        return;\n      }\n\n      if (this.configuration.toggleOnHover) {\n        this.doShow();\n      }\n    },\n    mouseleaveHandler(e: MouseEvent): void {\n      this.$emit('mouseleave', e);\n\n      if (this.isTouchOnlyDevice) {\n        return;\n      }\n\n      if (this.configuration.toggleOnHover && !this.targetIsChild(e.relatedTarget)) {\n        this.hideAfterTimeout();\n      }\n    },\n    touchstartHandler(e: TouchEvent) {\n      this.$emit('touchstart', e);\n\n      if (Array.from(e.targetTouches).some((touch) => this.targetIsChild(touch.target))) {\n        return;\n      }\n\n      if (this.configuration.toggleOnFocus || this.configuration.toggleOnHover) {\n        this.doHide();\n      }\n    },\n    hideAfterTimeout(): void {\n      if (!this.configuration.hideOnLeaveTimeout) {\n        this.doHide();\n      } else {\n        this.hideTimeout = setTimeout(() => {\n          this.doHide();\n          this.hideTimeout = null;\n        }, this.configuration.hideOnLeaveTimeout);\n      }\n    },\n  },\n});\n\n</script>\n"
  },
  {
    "path": "src/components/TInput.vue",
    "content": "<template>\n  <input\n    v-if=\"usesVModel\"\n    v-model=\"localValue\"\n    v-bind=\"attributes\"\n  >\n  <input\n    v-else\n    v-bind=\"attributes\"\n  >\n</template>\n\n<script lang=\"ts\">\nimport { TInputConfig } from '@variantjs/core';\nimport { defineComponent, PropType, getCurrentInstance } from 'vue';\nimport { TInputOptions, TInputValue } from '../types/components/t-input';\nimport { getVariantProps } from '../utils/getVariantProps';\nimport useVModel from '../use/useVModel';\nimport useConfiguration from '../use/useConfiguration';\n\nexport default defineComponent({\n  name: 'TInput',\n  compatConfig: {\n    MODE: 3,\n  },\n  props: {\n    ...getVariantProps<TInputOptions>(),\n    modelValue: {\n      type: [String, Number] as PropType<TInputValue>,\n      default: undefined,\n    },\n  },\n  setup(props) {\n    const vm = getCurrentInstance();\n\n    const definedProps = vm!.vnode.props;\n\n    const usesVModel = definedProps && definedProps.modelValue !== undefined;\n\n    const localValue = useVModel(props, 'modelValue');\n\n    const { configuration, attributes } = useConfiguration<TInputOptions>(TInputConfig);\n\n    return {\n      localValue, configuration, attributes, usesVModel,\n    };\n  },\n});\n</script>\n"
  },
  {
    "path": "src/components/TInputGroup.vue",
    "content": "<template>\n  <component\n    :is=\"tagName\"\n    ref=\"wrapper\"\n    :class=\"configuration.classesList?.wrapper\"\n    v-bind=\"attributes\"\n  >\n    <component\n      :is=\"element.tagName\"\n      v-for=\"element in elementsToRender\"\n      :key=\"element.name\"\n      :ref=\"element.name\"\n      :class=\"configuration.classesList?.[element.name === 'default' ? 'body' : element.name]\"\n    >\n      <slot\n        v-if=\"$slots[element.name]\"\n        :name=\"element.name\"\n      />\n      <template v-else>\n        {{ configuration[element.name === 'default' ? 'body' : element.name] }}\n      </template>\n    </component>\n  </component>\n</template>\n\n<script lang=\"ts\">\nimport { TInputGroupConfig, TInputGroupClassesKeys, TInputGroupClassesValidKeys } from '@variantjs/core';\nimport { defineComponent, PropType } from 'vue';\nimport { TInputGroupOptions, TInputGroupValidChilElementsKeys } from '../types';\nimport useConfigurationWithClassesList from '../use/useConfigurationWithClassesList';\nimport { getVariantPropsWithClassesList } from '../utils/getVariantProps';\n\n// @vue/component\nexport default defineComponent({\n  name: 'TInputGroup',\n  compatConfig: {\n    MODE: 3,\n  },\n  props: {\n    ...getVariantPropsWithClassesList<TInputGroupOptions, TInputGroupClassesValidKeys>(),\n    label: {\n      type: String,\n      default: undefined,\n    },\n    description: {\n      type: String,\n      default: undefined,\n    },\n    feedback: {\n      type: String,\n      default: undefined,\n    },\n    body: {\n      type: String,\n      default: undefined,\n    },\n    tagName: {\n      type: String,\n      default: 'div',\n    },\n    bodyTagName: {\n      type: String,\n      default: 'div',\n    },\n    labelTagName: {\n      type: String,\n      default: 'label',\n    },\n    feedbackTagName: {\n      type: String,\n      default: 'div',\n    },\n    descriptionTagName: {\n      type: String,\n      default: 'div',\n    },\n    sortedElements: {\n      type: Array as PropType<TInputGroupValidChilElementsKeys>,\n      default: (): TInputGroupValidChilElementsKeys => (['label', 'default', 'feedback', 'description']),\n      validator: (value: Array<string>): boolean => {\n        const expectedValues: TInputGroupValidChilElementsKeys = ['default', 'description', 'feedback', 'label'];\n        return value.every((key) => expectedValues.find((k) => k === key) !== null);\n      },\n    },\n  },\n  setup() {\n    const { configuration, attributes } = useConfigurationWithClassesList<TInputGroupOptions>(TInputGroupConfig, TInputGroupClassesKeys);\n\n    return { configuration, attributes };\n  },\n  computed: {\n    elementsToRender(): Array<{\n      name: 'label' | 'default' | 'feedback' | 'description',\n      tagName: string,\n    }> {\n      const { configuration } = this;\n      const slots = this.$slots;\n      return (this.sortedElements)\n        .filter((e) => (e === 'default' ? (!!configuration.body || !!slots.default) : (!!configuration[e] || !!slots[e])))\n        .map((e) => ({\n          name: e,\n          tagName: (e === 'default' ? configuration.bodyTagName : configuration[`${e}TagName`]) as string,\n        }));\n    },\n  },\n});\n</script>\n"
  },
  {
    "path": "src/components/TModal.vue",
    "content": "<template>\n  <teleport\n    v-if=\"showComponent\"\n    :to=\"configuration.teleportTo\"\n    :disabled=\"! configuration.teleport\"\n  >\n    <transitionable :classes-list=\"overlayTransitionClassesList\">\n      <div\n        v-show=\"showOverlay\"\n        v-bind=\"attributes\"\n        ref=\"overlay\"\n        tabindex=\"0\"\n        :class=\"configuration.classesList?.overlay\"\n        @keydown.escape=\"onKeydownEscapeHandler\"\n        @click=\"onClickHandler\"\n      >\n        <transitionable :classes-list=\"configuration.classesList\">\n          <div\n            v-show=\"showModal\"\n            v-bind=\"configuration.modalAttributes\"\n            ref=\"modal\"\n            :class=\"configuration.classesList?.wrapper\"\n            @click.stop\n          >\n            <template v-if=\"noBody\">\n              <slot />\n            </template>\n            <div\n              v-else\n              :class=\"configuration.classesList?.modal\"\n            >\n              <slot\n                v-if=\"!configuration.hideCloseButton\"\n                name=\"closeButton\"\n                :hide=\"hide\"\n              >\n                <button\n                  type=\"button\"\n                  :class=\"configuration.classesList?.close\"\n                  @click=\"hide(ModalHideReason.Close)\"\n                >\n                  <slot\n                    name=\"closeButtonIcon\"\n                    :hide=\"hide\"\n                  >\n                    <close-icon :class=\"configuration.classesList?.closeIcon\" />\n                  </slot>\n                </button>\n              </slot>\n\n              <div\n                v-if=\"$slots.header || configuration.header\"\n                ref=\"header\"\n                :class=\"configuration.classesList?.header\"\n              >\n                <slot\n                  name=\"header\"\n                  :hide=\"hide\"\n                >\n                  {{ configuration.header }}\n                </slot>\n              </div>\n\n              <div\n                v-if=\"$slots.default || configuration.body\"\n                ref=\"body\"\n                :class=\"configuration.classesList?.body\"\n              >\n                <slot :hide=\"hide\">\n                  {{ configuration.body }}\n                </slot>\n              </div>\n\n              <div\n                v-if=\"$slots.footer || configuration.footer\"\n                ref=\"footer\"\n                :class=\"configuration.classesList?.footer\"\n              >\n                <slot\n                  name=\"footer\"\n                  :hide=\"hide\"\n                >\n                  {{ configuration.footer }}\n                </slot>\n              </div>\n            </div>\n          </div>\n        </transitionable>\n      </div>\n    </transitionable>\n  </teleport>\n</template>\n\n<script lang=\"ts\">\nimport {\n  defineComponent, PropType, ref, watch, nextTick, onBeforeUnmount, onMounted, HTMLAttributes, inject, computed,\n} from 'vue';\nimport { BodyScrollOptions, disableBodyScroll, enableBodyScroll } from 'body-scroll-lock';\nimport {\n  Data, TModalConfig, TModalClassesKeys, TModalClassesValidKeys, ModalHideReason,\n} from '@variantjs/core';\nimport { TModalOptions, EmitterInterface } from '../types';\nimport useConfigurationWithClassesList from '../use/useConfigurationWithClassesList';\nimport { getVariantPropsWithClassesList } from '../utils/getVariantProps';\nimport CloseIcon from '../icons/CloseIcon.vue';\nimport useVModel from '../use/useVModel';\nimport Transitionable from './misc/Transitionable.vue';\n\n// @vue/component\nexport default defineComponent({\n  name: 'TModal',\n  compatConfig: {\n    MODE: 3,\n  },\n  components: {\n    CloseIcon,\n    Transitionable,\n  },\n  props: {\n    ...getVariantPropsWithClassesList<TModalOptions, TModalClassesValidKeys>(),\n    name: {\n      type: String,\n      default: undefined,\n    },\n    modelValue: {\n      type: Boolean,\n      default: false,\n    },\n    modalAttributes: {\n      type: Object as PropType<HTMLAttributes & Data>,\n      default: () => ({}),\n    },\n    header: {\n      type: String,\n      default: undefined,\n    },\n    body: {\n      type: String,\n      default: undefined,\n    },\n    footer: {\n      type: String,\n      default: undefined,\n    },\n    focusOnOpen: {\n      type: Boolean,\n      default: true,\n    },\n    clickToClose: {\n      type: Boolean,\n      default: true,\n    },\n    escToClose: {\n      type: Boolean,\n      default: true,\n    },\n    disableBodyScroll: {\n      type: Boolean,\n      default: true,\n    },\n    noBody: {\n      type: Boolean,\n      default: false,\n    },\n    hideCloseButton: {\n      type: Boolean,\n      default: false,\n    },\n    bodyScrollLockOptions: {\n      type: Object as PropType<BodyScrollOptions>,\n      default: () => ({}),\n    },\n    teleport: {\n      type: Boolean,\n      default: true,\n    },\n    teleportTo: {\n      type: [String, Object] as PropType<string | HTMLElement>,\n      default: 'body',\n    },\n  },\n  emits: {\n    shown: () => true,\n    // eslint-disable-next-line @typescript-eslint/no-unused-vars\n    hidden: (reason: ModalHideReason) => true,\n    // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any\n    'before-show': ({ cancel, params }: { cancel: (reason?: any) => void, params: any }) => true,\n    // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any\n    'before-hide': ({ cancel, reason }: { cancel: (reason?: any) => void, reason: ModalHideReason }) => true,\n    'update:modelValue': () => true,\n  },\n  setup(props, { emit }) {\n    const { configuration, attributes } = useConfigurationWithClassesList<TModalOptions>(TModalConfig, TModalClassesKeys);\n\n    const overlay = ref<HTMLDivElement>();\n\n    let modalParameters: unknown;\n\n    const showModel = useVModel(props, 'modelValue');\n\n    const scrollIsDisabled = ref<boolean>(false);\n    \n    const showComponent = ref(showModel.value);\n\n    const showOverlay = ref(showModel.value);\n\n    const showModal = ref(showModel.value);\n\n    const hideReason = ref<ModalHideReason>(ModalHideReason.Value);\n\n    const canceled = ref(false);\n\n    const hide = (reason: ModalHideReason = ModalHideReason.Other) :void => {\n      hideReason.value = reason;\n\n      showModel.value = false;\n    };\n\n    const show = (params: unknown) :void => {\n      modalParameters = params;\n\n      showModel.value = true;\n    };\n\n    const focusModal = () :void => {\n      overlay.value!.focus();\n    };\n\n    const disableBodyScrollIfNeccesary = () => {\n      if (!configuration.disableBodyScroll || scrollIsDisabled.value) {\n        return ;\n      }\n\n      disableBodyScroll(overlay.value!, configuration.bodyScrollLockOptions);\n      \n      scrollIsDisabled.value = true;\n    };\n\n    const enableBodyScrollIfNeccesary = () => {\n      if (! scrollIsDisabled.value) {\n        return;\n      }\n\n      enableBodyScroll(overlay.value!);\n      \n      scrollIsDisabled.value = false;\n    };\n\n    const initModal = () :void => {\n      if (configuration.focusOnOpen) {\n        focusModal();\n      }\n\n      disableBodyScrollIfNeccesary();      \n    };\n\n    const reset = () :void => {\n      modalParameters = undefined;\n      hideReason.value = ModalHideReason.Value;\n    };\n\n    const onBeforeShow = () : Promise<void> => new Promise((resolve, reject) => {\n      emit('before-show', {\n        cancel: reject,\n        params: modalParameters,\n      });\n\n      resolve();\n    });\n\n    const onBeforeHide = () : Promise<void> => new Promise((resolve, reject) => {\n      emit('before-hide', {\n        cancel: reject,\n        reason: hideReason.value,\n      });\n\n      enableBodyScrollIfNeccesary();\n\n      resolve();\n    });\n\n    const onShown = () :void => {\n      emit('shown');\n\n      initModal();\n    };\n\n    const onHidden = () :void => {\n      emit('hidden', hideReason.value);\n\n      reset();\n    };\n\n    watch(showModel, async (isShow: boolean): Promise<void> => {\n      if (canceled.value) {\n        canceled.value = false;\n        return;\n      }\n\n      if (isShow) {\n        try {\n          await onBeforeShow();\n        } catch (e) {\n          canceled.value = true;\n          showModel.value = false;\n          return;\n        }\n\n        showComponent.value = true;\n\n        nextTick(() => {\n          showOverlay.value = true;\n\n          nextTick(() => {\n            showModal.value = true;\n\n            nextTick(() => {\n              onShown();\n            });\n          });\n        });\n      } else {\n        try {\n          await onBeforeHide();\n        } catch (e) {\n          canceled.value = true;\n          showModel.value = true;\n          return;\n        }\n\n        showModal.value = false;\n\n        nextTick(() => {\n          showOverlay.value = false;\n\n          nextTick(() => {\n            showComponent.value = false;\n\n            nextTick(() => {\n              onHidden();\n            });\n          });\n        });\n      }\n    });\n\n    const onKeydownEscapeHandler = () :void => {\n      if (!configuration.escToClose) {\n        return;\n      }\n\n      hide(ModalHideReason.Esc);\n    };\n\n    const onClickHandler = () :void => {\n      if (!configuration.clickToClose) {\n        return;\n      }\n\n      hide(ModalHideReason.Outside);\n    };\n\n    onMounted(() => {\n      if (showModel.value) {\n        initModal();\n      }\n    });\n\n    onBeforeUnmount(() => {\n      reset();\n\n      enableBodyScrollIfNeccesary();\n    });\n\n    if (configuration.name) {\n      const emitter = inject<EmitterInterface>('emitter')!;\n\n      emitter.on('modal:show', (name, params) => {\n        if (configuration.name !== name) {\n          return;\n        }\n\n        show(params);\n      });\n\n      emitter.on('modal:hide', (name) => {\n        if (configuration.name !== name) {\n          return;\n        }\n\n        hide(ModalHideReason.Method);\n      });\n    }\n\n    const overlayTransitionClassesList = computed(() => ({\n      enterActiveClass: configuration.classesList!.overlayEnterActiveClass,\n      enterFromClass: configuration.classesList!.overlayEnterFromClass,\n      enterToClass: configuration.classesList!.overlayEnterToClass,\n      leaveActiveClass: configuration.classesList!.overlayLeaveActiveClass,\n      leaveFromClass: configuration.classesList!.overlayLeaveFromClass,\n      leaveToClass: configuration.classesList!.overlayLeaveToClass,\n    }));\n\n    return {\n      configuration,\n      attributes,\n      showOverlay,\n      showModal,\n      showComponent,\n      overlay,\n      overlayTransitionClassesList,\n      show,\n      hide,\n      focusModal,\n      onKeydownEscapeHandler,\n      onClickHandler,\n      ModalHideReason,\n    };\n  },\n});\n</script>\n"
  },
  {
    "path": "src/components/TRadio.vue",
    "content": "<template>\n  <input\n    v-model=\"localValue\"\n    type=\"radio\"\n    v-bind=\"attributes\"\n  >\n</template>\n\n<script lang=\"ts\">\nimport { TRadioConfig } from '@variantjs/core';\nimport { defineComponent, PropType } from 'vue';\nimport { TRadioOptions, TRadioValue } from '../types';\nimport useConfiguration from '../use/useConfiguration';\nimport useVModel from '../use/useVModel';\nimport { getVariantProps } from '../utils/getVariantProps';\n\n// @vue/component\nexport default defineComponent({\n  name: 'TRadio',\n  compatConfig: {\n    MODE: 3,\n  },\n  props: {\n    ...getVariantProps<TRadioOptions>(),\n    modelValue: {\n      type: [String, Number, Boolean, Array, Object, Date, Function, Symbol] as PropType<TRadioValue>,\n      default: undefined,\n    },\n  },\n  setup(props) {\n    const localValue = useVModel(props, 'modelValue');\n    const { configuration, attributes } = useConfiguration<TRadioOptions>(TRadioConfig);\n\n    return { localValue: localValue as any, configuration, attributes };\n  },\n});\n\n</script>\n"
  },
  {
    "path": "src/components/TRichSelect/RichSelectClearButton.vue",
    "content": "<template>\n  <button\n    type=\"button\"\n    data-rich-select-focusable\n    :class=\"className\"\n  >\n    <slot name=\"clearButton\">\n      <close-icon class=\"w-4 h-4\" />\n    </slot>\n  </button>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\nimport CloseIcon from '../../icons/CloseIcon.vue';\nimport useInjectsClassesListClass from '../../use/useInjectsClassesListClass';\n\nexport default defineComponent({\n  name: 'RichSelectClearButton',\n  compatConfig: {\n    MODE: 3,\n  },\n  components: {\n    CloseIcon,\n  },\n  setup() {\n    const className = useInjectsClassesListClass('clearButton');\n\n    return { className };\n  },\n});\n</script>\n"
  },
  {
    "path": "src/components/TRichSelect/RichSelectDropdown.vue",
    "content": "<template>\n  <div :class=\"className\">\n    <rich-select-search-input\n      v-if=\"showSearchInput\"\n      ref=\"searchInput\"\n    />\n\n    <slot name=\"dropdownTop\" />\n\n    <rich-select-state ref=\"state\">\n      <template #stateFeedback=\"props\">\n        <slot\n          name=\"stateFeedback\"\n          v-bind=\"props\"\n        />\n      </template>\n    </rich-select-state>\n\n    <rich-select-options-list\n      ref=\"optionsList\"\n      :options=\"options\"\n    >\n      <template #option=\"props\">\n        <slot\n          name=\"option\"\n          v-bind=\"props\"\n        />\n      </template>\n      <template #optionLabel=\"props\">\n        <slot\n          name=\"optionLabel\"\n          v-bind=\"props\"\n        />\n      </template>\n      <template #optionIcon=\"props\">\n        <slot\n          name=\"optionIcon\"\n          v-bind=\"props\"\n        />\n      </template>\n    </rich-select-options-list>\n\n    <slot name=\"dropdownButton\" />\n  </div>\n</template>\n\n<script lang=\"ts\">\nimport {\n  ComputedRef, defineComponent, inject,\n} from 'vue';\nimport { NormalizedOptions } from '@variantjs/core';\nimport RichSelectOptionsList from './RichSelectOptionsList.vue';\nimport RichSelectSearchInput from './RichSelectSearchInput.vue';\nimport RichSelectState from './RichSelectState.vue';\nimport useInjectsClassesListClass from '../../use/useInjectsClassesListClass';\n\nexport default defineComponent({\n  name: 'RichSelectDropdown',\n  compatConfig: {\n    MODE: 3,\n  },\n  components: {\n    RichSelectOptionsList,\n    RichSelectSearchInput,\n    RichSelectState,\n  },\n  setup() {\n    const options = inject<ComputedRef<NormalizedOptions>>('options')!;\n    const showSearchInput = inject<ComputedRef<boolean>>('showSearchInput')!;\n    const className = useInjectsClassesListClass('dropdownContent');\n\n    return {\n      options,\n      showSearchInput,\n      className,\n    };\n  },\n});\n</script>\n"
  },
  {
    "path": "src/components/TRichSelect/RichSelectOption.vue",
    "content": "<template>\n  <li\n    v-if=\"hasChildren\"\n    role=\"optgroup\"\n    :class=\"classesList.optgroup\"\n  >\n    <div :class=\"classesList.optgroupContent\">\n      <span :class=\"classesList.optgroupLabel\">{{ option.text }}</span>\n\n      <rich-select-options-list\n        ref=\"childrenOptions\"\n        :class=\"classesList.optgroupOptionsList\"\n        :options=\"option.children\"\n        :deep=\"deep + 1\"\n      />\n    </div>\n  </li>\n  <li\n    v-else\n    :class=\"classesList.optionWrapper\"\n    @mousemove=\"mousemoveHandler\"\n    @mousewheel=\"mousewheelHandler\"\n    @click=\"clickHandler\"\n  >\n    <slot\n      name=\"option\"\n      :class-name=\"optionClasses\"\n      :option=\"option\"\n      :is-disabled=\"isDisabled\"\n      :is-active=\"isActive\"\n      :is-selected=\"isSelected\"\n      :deep=\"deep\"\n    >\n      <button\n        role=\"option\"\n        :class=\"optionClasses\"\n        :aria-selected=\"isSelected\"\n        tabindex=\"-1\"\n        type=\"button\"\n        :disabled=\"isDisabled\"\n        :value=\"valueAttribute\"\n      >\n        <div :class=\"classesList.optionContent\">\n          <slot\n            name=\"optionLabel\"\n            :option=\"option\"\n            :is-disabled=\"isDisabled\"\n            :is-active=\"isActive\"\n            :is-selected=\"isSelected\"\n            :deep=\"deep\"\n          >\n            <span :class=\"classesList.optionLabel\">\n              {{ option.text }}\n            </span>\n          </slot>\n\n          <slot\n            name=\"optionIcon\"\n            :class-name=\"optionClasses\"\n            :option=\"option\"\n            :is-disabled=\"isDisabled\"\n            :is-active=\"isActive\"\n            :is-selected=\"isSelected\"\n            :deep=\"deep\"\n          >\n            <checkmark-icon\n              v-if=\"isSelected\"\n              ref=\"checkIcon\"\n              :class=\"classesList.optionSelectedIcon\"\n            />\n          </slot>\n        </div>\n      </button>\n    </slot>\n  </li>\n</template>\n\n<script lang=\"ts\">\nimport {\n  defineComponent, inject, PropType, Ref, defineAsyncComponent,\n} from 'vue';\nimport { CSSClass, NormalizedOption, normalizedOptionIsDisabled } from '@variantjs/core';\nimport useInjectsClassesList from '../../use/useInjectsClassesList';\nimport CheckmarkIcon from '../../icons/CheckmarkIcon.vue';\n\nexport default defineComponent({\n  name: 'RichSelectOption',\n  compatConfig: {\n    MODE: 3,\n  },\n  components: {\n    CheckmarkIcon,\n  },\n  props: {\n    option: {\n      type: [Object] as PropType<NormalizedOption>,\n      required: true,\n    },\n    deep: {\n      type: Number,\n      default: 0,\n    },\n  },\n  setup() {\n    const toggleOption = inject<(option: NormalizedOption) => void>('toggleOption')!;\n    const setActiveOption = inject<(option: NormalizedOption) => void>('setActiveOption')!;\n    const optionIsSelected = inject<(option: NormalizedOption) => boolean>('optionIsSelected')!;\n    const optionIsActive = inject<(option: NormalizedOption) => boolean>('optionIsActive')!;\n    const shown = inject<Ref<boolean>>('shown');\n    const classesList = useInjectsClassesList()!;\n\n    return {\n      setActiveOption,\n      toggleOption,\n      optionIsSelected,\n      optionIsActive,\n      shown,\n      classesList,\n    };\n  },\n  computed: {\n    optionClasses(): CSSClass[] {\n      const classes: CSSClass[] = [this.classesList!.option];\n\n      // Selected\n      if (this.isSelected) {\n        if (this.isActive) {\n          classes.push(this.classesList!.selectedHighlightedOption);\n        } else {\n          classes.push(this.classesList!.selectedOption);\n        }\n      // Not selected\n      } else if (this.isActive) {\n        classes.push(this.classesList!.highlightedOption);\n      }\n\n      return classes;\n    },\n    valueAttribute(): string {\n      if (typeof this.option.value === 'object') {\n        return JSON.stringify(this.option.value);\n      }\n\n      return String(this.option.value);\n    },\n    hasChildren(): boolean {\n      return this.option.children !== undefined && this.option.children.length > 0;\n    },\n    isSelected(): boolean {\n      return this.optionIsSelected(this.option);\n    },\n    isActive(): boolean {\n      return this.optionIsActive(this.option);\n    },\n    isDisabled(): boolean {\n      return normalizedOptionIsDisabled(this.option);\n    },\n  },\n  watch: {\n    shown: {\n      async handler(): Promise<void> {\n        await this.$nextTick();\n        this.scrollIntoViewIfNeccesary();\n      },\n      immediate: true,\n    },\n    isActive(): void {\n      this.scrollIntoViewIfNeccesary();\n    },\n  },\n  beforeCreate() {\n    /* istanbul ignore next */\n    this.$options.components!.RichSelectOptionsList = defineAsyncComponent(() => import('./RichSelectOptionsList.vue'));\n  },\n  methods: {\n    scrollIntoViewIfNeccesary(): void {\n      if (this.shown && this.isActive) {\n        const li = this.$el as HTMLLIElement;\n        li.scrollIntoView({ block: 'nearest', behavior: 'smooth' });\n      }\n    },\n    mousemoveHandler(): void {\n      if (this.isDisabled) {\n        return;\n      }\n      this.setActiveOption(this.option);\n    },\n    mousewheelHandler(): void {\n      if (this.isDisabled) {\n        return;\n      }\n      this.setActiveOption(this.option);\n    },\n    clickHandler(): void {\n      if (this.isDisabled) {\n        return;\n      }\n      this.toggleOption(this.option);\n    },\n  },\n});\n</script>\n"
  },
  {
    "path": "src/components/TRichSelect/RichSelectOptionsList.vue",
    "content": "<template>\n  <ul\n    v-if=\"showOptions\"\n    :class=\"classesList.optionsList\"\n    :style=\"usesMaxHeight? `max-height: ${maxHeight}; overflow-x: auto;` : undefined\"\n  >\n    <rich-select-option\n      v-for=\"(option, index) in options\"\n      :key=\"`${deep > 0 ? `${deep}-` : ''}${JSON.stringify(option.value)}-${index}`\"\n      :option=\"option\"\n      :deep=\"deep\"\n    >\n      <template #option=\"props\">\n        <slot\n          name=\"option\"\n          v-bind=\"props\"\n        />\n      </template>\n      <template #optionLabel=\"props\">\n        <slot\n          name=\"optionLabel\"\n          v-bind=\"props\"\n        />\n      </template>\n      <template #optionIcon=\"props\">\n        <slot\n          name=\"optionIcon\"\n          v-bind=\"props\"\n        />\n      </template>\n    </rich-select-option>\n\n    <li\n      v-if=\"fetchingMoreOptions\"\n      ref=\"fetchingMoreOptionsText\"\n      key=\"loading_more\"\n      :class=\"classesList.optionsListLoadingMore\"\n      v-text=\"configuration.loadingMoreResultsText\"\n    />\n  </ul>\n</template>\n\n<script lang=\"ts\">\nimport {\n  computed,\n  Ref,\n  defineComponent, inject, PropType,\n} from 'vue';\nimport { debounce, NormalizedOptions, normalizeMeasure } from '@variantjs/core';\nimport RichSelectOption from './RichSelectOption.vue';\nimport { TRichSelectOptions } from '../../types';\nimport useInjectsClassesList from '../../use/useInjectsClassesList';\n\nexport default defineComponent({\n  name: 'RichSelectOptionsList',\n  compatConfig: {\n    MODE: 3,\n  },\n  components: {\n    RichSelectOption,\n  },\n  props: {\n    options: {\n      type: Array as PropType<NormalizedOptions>,\n      required: true,\n    },\n    deep: {\n      type: Number,\n      default: 0,\n    },\n  },\n  setup(props) {\n    const configuration = inject<TRichSelectOptions>('configuration')!;\n    const shown = inject<Ref<boolean>>('shown');\n    const fetchingMoreOptions = inject<Ref<boolean>>('fetchingMoreOptions')!;\n    const dropdownBottomReachedHandler = inject<(() => void)>('dropdownBottomReachedHandler')!;\n\n    const maxHeight = computed(() => normalizeMeasure(configuration.maxHeight));\n    const usesMaxHeight = computed((): boolean => props.deep === 0 && maxHeight.value !== undefined);\n\n    const classesList = useInjectsClassesList();\n\n    const bottomReachedObserver = debounce(([event]: [Event]) => {\n      const element = event.target as HTMLUListElement;\n      const reached: boolean = Math.ceil(element.scrollHeight - element.scrollTop) === element.clientHeight;\n\n      if (reached) {\n        dropdownBottomReachedHandler();\n      }\n    }, 200);\n\n    return {\n      maxHeight, usesMaxHeight, shown, bottomReachedObserver, fetchingMoreOptions, configuration, classesList,\n    };\n  },\n  computed: {\n    showOptions(): boolean {\n      return this.options.length > 0;\n    },\n  },\n  watch: {\n    async showOptions(show: boolean) {\n      if (show) {\n        await this.$nextTick();\n        this.$el.addEventListener('scroll', this.bottomReachedObserver);\n      } else {\n        this.$el.removeEventListener('scroll', this.bottomReachedObserver);\n      }\n    },\n    async fetchingMoreOptions(fetchingMoreOptions: boolean) {\n      if (fetchingMoreOptions) {\n        await this.$nextTick();\n        const el = this.$refs.fetchingMoreOptionsText as HTMLLIElement;\n        el.scrollIntoView({ block: 'end', behavior: 'smooth' });\n      }\n    },\n  },\n  mounted() {\n    if (this.showOptions) {\n      this.$el.addEventListener('scroll', this.bottomReachedObserver);\n    }\n  },\n  beforeUnmount() {\n    if (this.showOptions) {\n      this.$el.removeEventListener('scroll', this.bottomReachedObserver);\n    }\n  },\n});\n</script>\n"
  },
  {
    "path": "src/components/TRichSelect/RichSelectSearchInput.vue",
    "content": "<template>\n  <div :class=\"classesList.searchWrapper\">\n    <input\n      ref=\"search\"\n      v-model=\"searchQuery\"\n      data-rich-select-focusable\n      :placeholder=\"configuration.searchBoxPlaceholder\"\n      :class=\"classesList.searchInput\"\n      @keydown.down=\"keydownDownHandler\"\n      @keydown.up=\"keydownUpHandler\"\n      @keydown.enter=\"keydownEnterHandler\"\n      @keydown.esc=\"keydownEscHandler\"\n    >\n  </div>\n</template>\n\n<script lang=\"ts\">\nimport {\n  ComputedRef, defineComponent, inject, watch, ref, Ref,\n} from 'vue';\nimport { TRichSelectOptions } from '../../types/components/t-rich-select';\nimport useInjectsClassesList from '../../use/useInjectsClassesList';\nimport useInjectsConfiguration from '../../use/useInjectsConfiguration';\n\nexport default defineComponent({\n  name: 'RichSelectSearchInput',\n  compatConfig: {\n    MODE: 3,\n  },\n  setup() {\n    const search = ref<HTMLInputElement>();\n\n    const shown = inject<ComputedRef<boolean>>('shown')!;\n    const searchQuery = inject<Ref<string | undefined>>('searchQuery')!;\n    const configuration = useInjectsConfiguration<TRichSelectOptions>();\n    const keydownDownHandler = inject<(e: KeyboardEvent) => void>('keydownDownHandler');\n    const keydownUpHandler = inject<(e: KeyboardEvent) => void>('keydownUpHandler');\n    const keydownEnterHandler = inject<(e: KeyboardEvent) => void>('keydownEnterHandler');\n    const keydownEscHandler = inject<(e: KeyboardEvent) => void>('keydownEscHandler');\n    const classesList = useInjectsClassesList()!;\n\n    watch(shown, async (isShown: boolean) : Promise<void> => {\n      if (isShown) {\n        search.value!.focus();\n      }\n    });\n\n    return {\n      configuration,\n      shown,\n      search,\n      searchQuery,\n      classesList,\n      keydownUpHandler,\n      keydownDownHandler,\n      keydownEnterHandler,\n      keydownEscHandler,\n    };\n  },\n});\n</script>\n"
  },
  {
    "path": "src/components/TRichSelect/RichSelectState.vue",
    "content": "<template>\n  <slot\n    name=\"stateFeedback\"\n    :fetching-options=\"fetchingOptions\"\n    :needs-more-chars-to-fetch=\"needsMoreCharsToFetch\"\n    :no-results=\"noResults\"\n  >\n    <div\n      v-if=\"fetchingOptions\"\n      :class=\"classesList.searchingText\"\n      v-text=\"configuration.searchingText\"\n    />\n    <div\n      v-else-if=\"needsMoreCharsToFetch\"\n      :class=\"classesList.needsMoreCharsText\"\n      v-text=\"needsMoreCharsMessage\"\n    />\n    <div\n      v-else-if=\"noResults\"\n      :class=\"classesList.noResultsText\"\n      v-text=\"configuration.noResultsText\"\n    />\n  </slot>\n</template>\n\n<script lang=\"ts\">\nimport {\n  computed,\n  ComputedRef, defineComponent, inject, Ref,\n} from 'vue';\nimport { TRichSelectOptions } from '../../types/components/t-rich-select';\nimport useInjectsClassesList from '../../use/useInjectsClassesList';\nimport useInjectsConfiguration from '../../use/useInjectsConfiguration';\n\nexport default defineComponent({\n  name: 'RichSelectState',\n  compatConfig: {\n    MODE: 3,\n  },\n  setup() {\n    const options = inject<ComputedRef<TRichSelectOptions>>('options')!;\n    const fetchingOptions = inject<Ref<boolean>>('fetchingOptions')!;\n    const needsMoreCharsToFetch = inject<Ref<boolean>>('needsMoreCharsToFetch')!;\n    const needsMoreCharsMessage = inject<ComputedRef<string>>('needsMoreCharsMessage')!;\n    const configuration = useInjectsConfiguration<TRichSelectOptions>();\n    const noResults = computed<boolean>((): boolean => options.value.length === 0);\n    const classesList = useInjectsClassesList()!;\n\n    return {\n      noResults,\n      configuration,\n      fetchingOptions,\n      needsMoreCharsToFetch,\n      needsMoreCharsMessage,\n      classesList,\n    };\n  },\n});\n</script>\n"
  },
  {
    "path": "src/components/TRichSelect/RichSelectTrigger.vue",
    "content": "<template>\n  <slot\n    v-if=\"isFetchingOptionsWhileClosed || !hasSelectedOption\"\n    name=\"placeholder\"\n    :is-fetching-options-while-closed=\"isFetchingOptionsWhileClosed\"\n  >\n    <template v-if=\"isFetchingOptionsWhileClosed\">\n      <text-placeholder\n        ref=\"fetchingPlaceholder\"\n        class-property=\"selectButtonSearchingPlaceholder\"\n        :placeholder=\"configuration.loadingClosedPlaceholder\"\n      />\n      <loading-icon\n        ref=\"loadingIcon\"\n        :class=\"classesList.selectButtonLoadingIcon\"\n      />\n    </template>\n\n    <text-placeholder\n      v-else\n      ref=\"placeholder\"\n      class-property=\"selectButtonPlaceholder\"\n      :placeholder=\"configuration.placeholder\"\n    />\n  </slot>\n\n  <rich-select-trigger-tags v-else-if=\"usesTags\">\n    <template #tagCloseIcon=\"props\">\n      <slot\n        name=\"tagCloseIcon\"\n        v-bind=\"props\"\n      />\n    </template>\n    <template #tagLabel=\"props\">\n      <slot\n        name=\"tagLabel\"\n        v-bind=\"props\"\n      />\n    </template>\n  </rich-select-trigger-tags>\n\n  <span\n    v-else\n    ref=\"label\"\n    :class=\"classesList.selectButtonLabel\"\n  >\n    <slot\n      name=\"label\"\n      :label=\"label\"\n      :selected-option=\"selectedOption\"\n    >\n      {{ label }}\n    </slot>\n  </span>\n\n  <slot\n    v-if=\"showSelectorIcon\"\n    name=\"selectorIcon\"\n  >\n    <selector-icon\n      ref=\"selectorIcon\"\n      :class=\"classesList.selectButtonSelectorIcon\"\n    />\n  </slot>\n</template>\n\n<script lang=\"ts\">\nimport {\n  ComputedRef, defineComponent, inject, Ref,\n} from 'vue';\nimport { NormalizedOption } from '@variantjs/core';\nimport TextPlaceholder from '../misc/TextPlaceholder.vue';\nimport RichSelectTriggerTags from './RichSelectTriggerTags.vue';\nimport SelectorIcon from '../../icons/SelectorIcon.vue';\nimport LoadingIcon from '../../icons/LoadingIcon.vue';\nimport { TRichSelectOptions } from '../../types/components/t-rich-select';\nimport useInjectsClassesList from '../../use/useInjectsClassesList';\nimport useInjectsConfiguration from '../../use/useInjectsConfiguration';\n\nexport default defineComponent({\n  name: 'RichSelectTrigger',\n  compatConfig: {\n    MODE: 3,\n  },\n  components: {\n    RichSelectTriggerTags,\n    TextPlaceholder,\n    SelectorIcon,\n    LoadingIcon,\n  },\n  setup() {\n    const configuration = useInjectsConfiguration<TRichSelectOptions>();\n\n    const selectedOption = inject<ComputedRef<NormalizedOption | undefined | NormalizedOption[]>>('selectedOption')!;\n\n    const hasSelectedOption = inject<ComputedRef<boolean>>('hasSelectedOption')!;\n\n    const fetchingOptions = inject<Ref<boolean>>('fetchingOptions')!;\n\n    const shown = inject<ComputedRef<boolean>>('shown')!;\n\n    const usesTags = inject<ComputedRef<boolean>>('usesTags')!;\n\n    const classesList = useInjectsClassesList()!;\n\n    return {\n      selectedOption,\n      hasSelectedOption,\n      configuration,\n      fetchingOptions,\n      shown,\n      usesTags,\n      classesList,\n    };\n  },\n  computed: {\n    label(): string | undefined {\n      if (!this.hasSelectedOption) {\n        return undefined;\n      }\n\n      if (this.multiple) {\n        return (this.selectedOption as NormalizedOption[])\n          .map((o) => o.text).join(', ');\n      }\n\n      return String((this.selectedOption as NormalizedOption).text);\n    },\n    isFetchingOptionsWhileClosed(): boolean {\n      return this.fetchingOptions && !this.shown;\n    },\n    multiple(): boolean {\n      return Array.isArray(this.selectedOption);\n    },\n    showSelectorIcon(): boolean {\n      if (this.isFetchingOptionsWhileClosed) {\n        return false;\n      }\n\n      if (!this.configuration.clearable) {\n        return true;\n      }\n\n      return !this.hasSelectedOption || this.configuration.disabled === true;\n    },\n  },\n});\n</script>\n"
  },
  {
    "path": "src/components/TRichSelect/RichSelectTriggerTags.vue",
    "content": "<template>\n  <div\n    :class=\"className\"\n  >\n    <rich-select-trigger-tags-tag\n      v-for=\"(option, index) in selectedOptions\"\n      :key=\"`${option.value}-${index}`\"\n      :option=\"option\"\n    >\n      <template #tagCloseIcon=\"props\">\n        <slot\n          name=\"tagCloseIcon\"\n          v-bind=\"props\"\n        />\n      </template>\n      <template #tagLabel=\"props\">\n        <slot\n          name=\"tagLabel\"\n          v-bind=\"props\"\n        />\n      </template>\n    </rich-select-trigger-tags-tag>\n  </div>\n</template>\n\n<script lang=\"ts\">\nimport { NormalizedOption } from '@variantjs/core';\nimport { ComputedRef, defineComponent, inject } from 'vue';\nimport RichSelectTriggerTagsTag from './RichSelectTriggerTagsTag.vue';\nimport useInjectsClassesListClass from '../../use/useInjectsClassesListClass';\n\nexport default defineComponent({\n  name: 'RichSelectTriggerTags',\n  compatConfig: {\n    MODE: 3,\n  },\n  components: {\n    RichSelectTriggerTagsTag,\n  },\n  setup() {\n    const selectedOptions = inject<ComputedRef<NormalizedOption[]>>('selectedOption')!;\n    const className = useInjectsClassesListClass('tagsWrapper')!;\n\n    return {\n      selectedOptions,\n      className,\n    };\n  },\n});\n</script>\n"
  },
  {
    "path": "src/components/TRichSelect/RichSelectTriggerTagsTag.vue",
    "content": "<template>\n  <button\n    type=\"button\"\n    :class=\"classesList.tag\"\n    :disabled=\"isDisabled\"\n    data-rich-select-focusable\n    data-rich-select-tag\n    :data-value=\"dataValueAttribute\"\n    @mousedown.prevent.stop=\"focus\"\n    @keydown.backspace.prevent.stop=\"unselect\"\n    @keydown.right.prevent.stop=\"focusNextElement\"\n    @keydown.left.prevent.stop=\"focusPrevElement\"\n    @keydown.enter.prevent.stop\n  >\n    <span :class=\"classesList.tagLabel\">\n      <slot\n        name=\"tagLabel\"\n        :option=\"option\"\n        :is-disabled=\"isDisabled\"\n      >{{ option.text }}</slot>\n    </span>\n\n    <span\n      v-if=\"!isDisabled\"\n      tabindex=\"0\"\n      :class=\"classesList.tagDeleteButton\"\n      data-rich-select-focusable\n      @mousedown.prevent.stop=\"unselect\"\n      @keydown.backspace.prevent.stop=\"unselect\"\n      @keydown.enter.prevent.stop=\"unselect\"\n    >\n      <slot\n        name=\"tagCloseIcon\"\n        :option=\"option\"\n      >\n        <close-icon\n          ref=\"closeIcon\"\n          :class=\"classesList.tagDeleteButtonIcon\"\n        />\n      </slot>\n    </span>\n  </button>\n</template>\n\n<script lang=\"ts\">\n\nimport { NormalizedOption, normalizedOptionIsDisabled } from '@variantjs/core';\nimport { defineComponent, inject, PropType } from 'vue';\nimport CloseIcon from '../../icons/CloseIcon.vue';\nimport useInjectsClassesList from '../../use/useInjectsClassesList';\n\nexport default defineComponent({\n  name: 'RichSelectTriggerTagsTag',\n  compatConfig: {\n    MODE: 3,\n  },\n  components: {\n    CloseIcon,\n  },\n  props: {\n    option: {\n      type: Object as PropType<NormalizedOption>,\n      required: true,\n    },\n  },\n  setup() {\n    const toggleOption = inject<(option: NormalizedOption) => void>('toggleOption')!;\n\n    const classesList = useInjectsClassesList()!;\n\n    return { toggleOption, classesList };\n  },\n  computed: {\n    dataValueAttribute(): string {\n      if (typeof this.option.value === 'object') {\n        return JSON.stringify(this.option.value);\n      }\n\n      return String(this.option.value);\n    },\n    isDisabled(): boolean {\n      return normalizedOptionIsDisabled(this.option);\n    },\n  },\n  methods: {\n    focus(): void {\n      this.$el.focus();\n    },\n    getElementIndex(): number {\n      const elements: HTMLElement[] = Array.from(this.$el.parentElement.children);\n\n      return Array.from(elements).findIndex((el) => el.isSameNode(this.$el));\n    },\n    focusNextElement(): void {\n      const { parentElement } = this.$el;\n      const currentElementIndex = this.getElementIndex();\n      const elements: HTMLElement[] = Array.from(parentElement.children);\n\n      if (currentElementIndex < elements.length - 1) {\n        elements[currentElementIndex + 1].focus();\n      }\n    },\n    focusPrevElement(): void {\n      const { parentElement } = this.$el;\n      const currentElementIndex = this.getElementIndex();\n      const elements: HTMLElement[] = Array.from(parentElement.children);\n\n      if (currentElementIndex > 0) {\n        elements[currentElementIndex - 1].focus();\n      }\n    },\n    async unselect(): Promise<void> {\n      const { parentElement } = this.$el;\n      const elementIndex = this.getElementIndex();\n\n      this.toggleOption(this.option);\n\n      await this.$nextTick();\n\n      const nextElement: HTMLElement | undefined = parentElement.children[elementIndex];\n\n      if (nextElement) {\n        nextElement.focus();\n      } else if (elementIndex > 0) {\n        parentElement.children[elementIndex - 1].focus();\n      }\n    },\n  },\n});\n</script>\n"
  },
  {
    "path": "src/components/TRichSelect.vue",
    "content": "<template>\n  <div\n    :class=\"configuration.classesList?.wrapper\"\n    v-bind=\"attributes\"\n  >\n    <t-select\n      v-model=\"localValue\"\n      :name=\"configuration.name\"\n      style=\"display: none\"\n      :fixed-classes=\"undefined\"\n      :classes=\"undefined\"\n      :multiple=\"configuration.multiple\"\n      :options=\"flattenedOptions\"\n    />\n\n    <t-dropdown\n      ref=\"dropdownComponent\"\n      :disabled=\"configuration.disabled\"\n      :classes=\"dropdownClasses\"\n      :fixed-classes=\"undefined\"\n      :toggle-on-focus=\"false\"\n      :toggle-on-click=\"false\"\n      :toggle-on-hover=\"false\"\n      :popper-options=\"configuration.dropdownPopperOptions\"\n      :placement=\"configuration.dropdownPlacement\"\n      :tag-name=\"usesTags ? 'div' : 'button'\"\n      :tabindex=\"usesTags && !hasSelectedOption ? 0 : undefined\"\n      :teleport=\"configuration.teleport\"\n      :teleport-to=\"configuration.teleportTo\"\n      data-rich-select-focusable\n      @mouseover=\"$emit('mouseover', $event)\"\n      @mouseleave=\"$emit('mouseleave', $event)\"\n      @touchstart=\"$emit('touchstart', $event)\"\n      @shown=\"shownHandler\"\n      @hidden=\"hiddenHandler\"\n      @before-show=\"beforeShowHandler\"\n      @before-hide=\"beforeHideHandler\"\n      @blur=\"blurHandler\"\n      @focus=\"focusHandler\"\n      @keydown.enter=\"keydownEnterHandler\"\n      @keydown.space=\"keydownSpaceHandler\"\n      @keydown.down=\"keydownDownHandler\"\n      @keydown.up=\"keydownUpHandler\"\n      @keydown.esc=\"keydownEscHandler\"\n      @mousedown=\"mousedownHandler\"\n      @blur-on-child=\"blurOnChildHandler\"\n    >\n      <template #trigger>\n        <rich-select-trigger ref=\"trigger\">\n          <template #selectorIcon=\"props\">\n            <slot\n              name=\"selectorIcon\"\n              v-bind=\"props\"\n            />\n          </template>\n          <template #placeholder=\"props\">\n            <slot\n              name=\"placeholder\"\n              v-bind=\"props\"\n            />\n          </template>\n          <template #label=\"props\">\n            <slot\n              name=\"label\"\n              v-bind=\"props\"\n            />\n          </template>\n          <template #tagCloseIcon=\"props\">\n            <slot\n              name=\"tagCloseIcon\"\n              v-bind=\"props\"\n            />\n          </template>\n          <template #tagLabel=\"props\">\n            <slot\n              name=\"tagLabel\"\n              v-bind=\"props\"\n            />\n          </template>\n        </rich-select-trigger>\n      </template>\n\n      <rich-select-dropdown ref=\"dropdown\">\n        <template #option=\"props\">\n          <slot\n            name=\"option\"\n            v-bind=\"props\"\n          />\n        </template>\n        <template #optionLabel=\"props\">\n          <slot\n            name=\"optionLabel\"\n            v-bind=\"props\"\n          />\n        </template>\n        <template #optionIcon=\"props\">\n          <slot\n            name=\"optionIcon\"\n            v-bind=\"props\"\n          />\n        </template>\n        <template #dropdownTop=\"props\">\n          <slot\n            name=\"dropdownTop\"\n            v-bind=\"props\"\n          />\n        </template>\n        <template #dropdownButton=\"props\">\n          <slot\n            name=\"dropdownButton\"\n            v-bind=\"props\"\n          />\n        </template>\n        <template #stateFeedback=\"props\">\n          <slot\n            name=\"stateFeedback\"\n            v-bind=\"props\"\n          />\n        </template>\n      </rich-select-dropdown>\n    </t-dropdown>\n\n    <rich-select-clear-button\n      v-if=\"showClearButton\"\n      ref=\"clearButton\"\n      @click=\"clearValue\"\n    >\n      <template #clearButton=\"props\">\n        <slot\n          name=\"clearButton\"\n          v-bind=\"props\"\n          :classes-list=\"configuration.classesList\"\n        />\n      </template>\n    </rich-select-clear-button>\n  </div>\n</template>\n\n<script lang=\"ts\">\nimport {\n  defineComponent, PropType, provide, ref, computed,\n} from 'vue';\nimport {\n  InputOptions,\n  TRichSelectConfig,\n  TRichSelectClassesKeys,\n  TRichSelectClassesValidKeys,\n  NormalizedOption,\n  CSSRawClassesList,\n  TDropdownPopperDefaultOptions as defaultPopperOptions,\n  isEqual,\n  throttle,\n  Measure,\n  Data,\n} from '@variantjs/core';\nimport { Options, Placement } from '@popperjs/core';\nimport useActivableOption from '../use/useActivableOption';\nimport useConfigurationWithClassesList from '../use/useConfigurationWithClassesList';\nimport useMulipleableVModel from '../use/useMulipleableVModel';\nimport useFetchsOptions from '../use/useFetchsOptions';\nimport useSelectableOption from '../use/useSelectableOption';\nimport { getVariantPropsWithClassesList } from '../utils/getVariantProps';\nimport {\n  FetchOptionsFn,\n  PreFetchOptionsFn,\n  MinimumInputLengthTextProp,\n  TRichSelectOptions,\n  TSelectValue,\n} from '../types';\nimport RichSelectTrigger from './TRichSelect/RichSelectTrigger.vue';\nimport RichSelectDropdown from './TRichSelect/RichSelectDropdown.vue';\nimport RichSelectClearButton from './TRichSelect/RichSelectClearButton.vue';\nimport TDropdown, { validDropdownPlacements } from './TDropdown.vue';\nimport TSelect from './TSelect.vue';\nimport { sameWidthModifier } from '../utils/popper';\n\n// @vue/component\nexport default defineComponent({\n  name: 'TRichSelect',\n  compatConfig: {\n    MODE: 3,\n  },\n  components: {\n    RichSelectTrigger,\n    RichSelectDropdown,\n    RichSelectClearButton,\n    TDropdown,\n    TSelect,\n  },\n  props: {\n    ...getVariantPropsWithClassesList<\n    TRichSelectOptions,\n    TRichSelectClassesValidKeys\n    >(),\n    modelValue: {\n      type: [\n        String,\n        Number,\n        Boolean,\n        Array,\n        Object,\n        Date,\n        Function,\n        Symbol,\n      ] as PropType<TSelectValue>,\n      default: undefined,\n    },\n    name: {\n      type: String,\n      default: undefined,\n    },\n    options: {\n      type: [Array, Object] as PropType<InputOptions>,\n      default: undefined,\n    },\n    normalizeOptions: {\n      type: Boolean,\n      default: true,\n    },\n    multiple: {\n      type: Boolean,\n      default: false,\n    },\n    disabled: {\n      type: Boolean,\n      default: false,\n    },\n    tags: {\n      type: Boolean,\n      default: false,\n    },\n    placeholder: {\n      type: String,\n      default: undefined,\n    },\n    dropdownPlacement: {\n      type: String as PropType<Placement>,\n      default: undefined,\n      validator: (value: string): boolean => validDropdownPlacements.includes(value),\n    },\n    dropdownPopperOptions: {\n      type: Object as PropType<Options>,\n      default: (): Options => ({\n        ...defaultPopperOptions,\n        placement: 'bottom',\n        modifiers: [\n          {\n            name: 'offset',\n            options: {\n              offset: [0, 8],\n            },\n          },\n          sameWidthModifier,\n        ],\n      } as Options),\n    },\n    closeOnSelect: {\n      type: Boolean,\n      default: undefined,\n    },\n    selectOnClose: {\n      type: Boolean,\n      default: false,\n    },\n    clearSearchOnClose: {\n      type: Boolean,\n      default: undefined,\n    },\n    toggleOnFocus: {\n      type: Boolean,\n      default: false,\n    },\n    toggleOnClick: {\n      type: Boolean,\n      default: true,\n    },\n    valueAttribute: {\n      type: String,\n      default: undefined,\n    },\n    textAttribute: {\n      type: String,\n      default: undefined,\n    },\n    hideSearchBox: {\n      type: Boolean,\n      default: false,\n    },\n    searchBoxPlaceholder: {\n      type: String,\n      default: 'Search...',\n    },\n    noResultsText: {\n      type: String,\n      default: 'No options found',\n    },\n    searchingText: {\n      type: String,\n      default: 'Searching...',\n    },\n    loadingClosedPlaceholder: {\n      type: String,\n      default: 'Loading...',\n    },\n    loadingMoreResultsText: {\n      type: String,\n      default: 'Loading more options...',\n    },\n    clearable: {\n      type: Boolean,\n      default: true,\n    },\n    maxHeight: {\n      type: [Number, String] as PropType<Measure | null>,\n      default: 250,\n    },\n    fetchOptions: {\n      type: Function as PropType<FetchOptionsFn>,\n      default: undefined,\n    },\n    prefetchOptions: {\n      type: [Function, Boolean] as PropType<PreFetchOptionsFn | boolean>,\n      default: false,\n    },\n    delay: {\n      type: Number,\n      default: 250,\n    },\n    minimumInputLength: {\n      type: Number,\n      default: undefined,\n    },\n    minimumInputLengthText: {\n      type: [Function, String] as PropType<MinimumInputLengthTextProp>,\n      default:\n        () => (minimumInputLength: number): string => `Please enter ${minimumInputLength} or more characters`,\n    },\n    minimumResultsForSearch: {\n      type: Number,\n      default: undefined,\n    },\n    teleport: {\n      type: Boolean,\n      default: false,\n    },\n    teleportTo: {\n      type: [String, Object] as PropType<string | HTMLElement>,\n      default: 'body',\n    },\n  },\n  emits: {\n    change: (e: CustomEvent) => e instanceof CustomEvent,\n    input: (e: CustomEvent) => e instanceof CustomEvent,\n    keydown: (e: KeyboardEvent) => e instanceof KeyboardEvent,\n    focus: (e: FocusEvent) => e instanceof FocusEvent,\n    blur: (e: FocusEvent) => e instanceof FocusEvent,\n    mousedown: (e: MouseEvent) => e instanceof MouseEvent,\n    mouseover: (e: MouseEvent) => e instanceof MouseEvent,\n    mouseleave: (e: MouseEvent) => e instanceof MouseEvent,\n    touchstart: (e: TouchEvent) => e instanceof TouchEvent,\n    shown: () => true,\n    hidden: () => true,\n    'before-show': () => true,\n    'before-hide': () => true,\n    'fetch-options-success': () => true,\n    'fetch-options-error': () => true,\n    'update:modelValue': () => true,\n  },\n  setup(props, { emit }) {\n    const { configuration, attributes } = useConfigurationWithClassesList<TRichSelectOptions>(\n      TRichSelectConfig,\n      TRichSelectClassesKeys,\n    );\n\n    const { localValue, clearValue } = useMulipleableVModel(\n      props,\n      'modelValue',\n      configuration,\n    );\n\n    const searchQuery = ref<string | undefined>(undefined);\n\n    const {\n      normalizedOptions,\n      flattenedOptions,\n      fetchsOptions,\n      needsMoreCharsToFetch,\n      needsMoreCharsMessage,\n      fetchingOptions,\n      fetchingMoreOptions,\n      fetchOptions: doFetchOptions,\n      prefetchOptions: doPrefetchOptions,\n      fetchMoreOptions,\n      optionsWereFetched,\n      fetchedOptionsHaveMorePages,\n      fetchOptionsCancel,\n    } = useFetchsOptions(\n      localValue,\n      computed(() => configuration.options as InputOptions | undefined),\n      computed(() => configuration.textAttribute),\n      computed(() => configuration.valueAttribute),\n      computed(() => configuration.normalizeOptions!),\n      searchQuery,\n      computed(() => configuration.fetchOptions),\n      computed(() => configuration.prefetchOptions!),\n      computed(() => configuration.delay),\n      computed(() => configuration.minimumInputLength),\n      computed(() => configuration.minimumInputLengthText!),\n    );\n\n    const {\n      selectedOption,\n      hasSelectedOption,\n      selectOption,\n      toggleOption,\n      optionIsSelected,\n    } = useSelectableOption(\n      flattenedOptions,\n      localValue,\n      computed(() => configuration.multiple!),\n    );\n\n    const {\n      activeOption,\n      optionIsActive,\n      setActiveOption,\n      initActiveOption,\n      setNextOptionActive,\n      setPrevOptionActive,\n    } = useActivableOption(flattenedOptions, localValue);\n\n    const shown = ref<boolean>(false);\n\n    const showSearchInput = computed<boolean>(() => {\n      if (configuration.hideSearchBox) {\n        return false;\n      }\n\n      if (configuration.minimumResultsForSearch !== undefined) {\n        return (\n          normalizedOptions.value.length\n          >= configuration.minimumResultsForSearch\n        );\n      }\n\n      return true;\n    });\n\n    /**\n     * Dropdown component reference\n     */\n    const dropdownComponent = ref<{\n      focus:() => void;\n      doShow: () => void;\n      doHide: () => void;\n      adjustPopper: () => Promise<void>;\n    }>();\n\n    const focusDropdownTrigger = (): void => {\n      dropdownComponent.value!.focus();\n    };\n\n    const usesTags = computed<boolean>(\n      () => configuration.tags === true && configuration.multiple === true,\n    );\n\n    /**\n     * Manage dropdown related methods\n     */\n    const hideDropdown = (): void => {\n      dropdownComponent.value!.doHide();\n    };\n\n    const showDropdown = (): void => {\n      dropdownComponent.value!.doShow();\n    };\n\n    const adjustDropdown = async (): Promise<void> => {\n      await dropdownComponent.value!.adjustPopper();\n    };\n\n    const throttledShowDropdown = throttle(showDropdown, 200);\n\n    const toggleDropdown = (): void => {\n      if (shown.value) {\n        hideDropdown();\n      } else {\n        throttledShowDropdown();\n      }\n    };\n\n    /**\n     * Active option handling\n     */\n    const toggleOptionFromActiveOption = (): void => {\n      if (activeOption.value === null) {\n        return;\n      }\n\n      toggleOption(activeOption.value as NormalizedOption);\n    };\n\n    // Select the current active option\n    const selectOptionFromActiveOption = (): void => {\n      if (activeOption.value === null) {\n        return;\n      }\n\n      selectOption(activeOption.value as NormalizedOption);\n    };\n\n    /**\n     * Event handlers\n     */\n    const keydownDownHandler = (e: KeyboardEvent): void => {\n      emit('keydown', e);\n\n      e.preventDefault();\n\n      if (shown.value === false) {\n        throttledShowDropdown();\n      } else {\n        setNextOptionActive();\n\n        const lastOption: NormalizedOption = normalizedOptions.value[normalizedOptions.value.length - 1];\n\n        if (\n          optionIsActive(lastOption)\n          && fetchedOptionsHaveMorePages.value\n          && !fetchingMoreOptions.value\n        ) {\n          fetchMoreOptions();\n        }\n      }\n    };\n\n    const keydownUpHandler = (e: KeyboardEvent): void => {\n      emit('keydown', e);\n\n      e.preventDefault();\n\n      if (shown.value === false) {\n        throttledShowDropdown();\n      } else {\n        setPrevOptionActive();\n      }\n    };\n\n    const keydownEnterHandler = (e: KeyboardEvent): void => {\n      emit('keydown', e);\n\n      if (shown.value === true) {\n        toggleOptionFromActiveOption();\n      }\n    };\n\n    const keydownSpaceHandler = (e: KeyboardEvent): void => {\n      emit('keydown', e);\n\n      e.preventDefault();\n\n      if (configuration.toggleOnClick && shown.value === false) {\n        throttledShowDropdown();\n      } else if (shown.value === true) {\n        toggleOptionFromActiveOption();\n      }\n    };\n\n    const keydownEscHandler = (e: KeyboardEvent): void => {\n      emit('keydown', e);\n\n      if (shown.value === false) {\n        return;\n      }\n\n      hideDropdown();\n\n      focusDropdownTrigger();\n    };\n\n    const dropdownBottomReachedHandler = (): void => {\n      if (fetchedOptionsHaveMorePages.value && !fetchingMoreOptions.value) {\n        fetchMoreOptions();\n      }\n    };\n\n    /**\n     * Provided data\n     */\n    provide('configuration', configuration);\n\n    provide('options', normalizedOptions);\n\n    provide('selectedOption', selectedOption);\n\n    provide('hasSelectedOption', hasSelectedOption);\n\n    provide('toggleOption', toggleOption);\n\n    provide('setActiveOption', setActiveOption);\n\n    provide('optionIsSelected', optionIsSelected);\n\n    provide('optionIsActive', optionIsActive);\n\n    provide('keydownDownHandler', keydownDownHandler);\n\n    provide('keydownUpHandler', keydownUpHandler);\n\n    provide('keydownEscHandler', keydownEscHandler);\n\n    provide('keydownEnterHandler', keydownEnterHandler);\n\n    provide('shown', shown);\n\n    provide('showSearchInput', showSearchInput);\n\n    provide('searchQuery', searchQuery);\n\n    provide('needsMoreCharsToFetch', needsMoreCharsToFetch);\n\n    provide('needsMoreCharsMessage', needsMoreCharsMessage);\n\n    provide('fetchingOptions', fetchingOptions);\n\n    provide('fetchingMoreOptions', fetchingMoreOptions);\n\n    provide('dropdownBottomReachedHandler', dropdownBottomReachedHandler);\n\n    provide('usesTags', usesTags);\n\n    return {\n      configuration,\n      attributes,\n      localValue,\n      activeOption,\n      hasSelectedOption,\n      shown,\n      dropdownComponent,\n      hideDropdown,\n      toggleDropdown,\n      throttledShowDropdown,\n      keydownDownHandler,\n      keydownUpHandler,\n      keydownSpaceHandler,\n      keydownEnterHandler,\n      keydownEscHandler,\n      focusDropdownTrigger,\n      optionIsSelected,\n      initActiveOption,\n      selectOption,\n      selectOptionFromActiveOption,\n      clearValue,\n      doFetchOptions,\n      doPrefetchOptions,\n      adjustDropdown,\n      fetchOptionsCancel,\n      fetchsOptions,\n      optionsWereFetched,\n      needsMoreCharsToFetch,\n      showSearchInput,\n      flattenedOptions,\n      usesTags,\n      searchQuery,\n    };\n  },\n  computed: {\n    canFetchOptions(): boolean {\n      return (\n        this.fetchsOptions\n        && !this.optionsWereFetched\n        && !this.needsMoreCharsToFetch\n      );\n    },\n    canPreFetchOptions(): boolean {\n      if (typeof this.configuration.prefetchOptions === 'function') {\n        return !this.optionsWereFetched;\n      }\n\n      return this.canFetchOptions;\n    },\n    dropdownClasses(): CSSRawClassesList {\n      const {\n        enterActiveClass,\n        enterFromClass,\n        enterToClass,\n        leaveActiveClass,\n        leaveFromClass,\n        leaveToClass,\n        trigger,\n        dropdown,\n      } = this.configuration.classesList!;\n\n      return {\n        trigger,\n        dropdown,\n        enterActiveClass,\n        enterFromClass,\n        enterToClass,\n        leaveActiveClass,\n        leaveFromClass,\n        leaveToClass,\n      };\n    },\n    showClearButton(): boolean {\n      return (\n        this.hasSelectedOption\n        && this.configuration.clearable === true\n        && this.configuration.disabled !== true\n      );\n    },\n  },\n  watch: {\n    localValue(): void {\n      this.onOptionSelected();\n    },\n  },\n  created() {\n    if (this.configuration.prefetchOptions && this.canPreFetchOptions) {\n      this.doPrefetchOptions();\n    }\n  },\n  beforeUnmount() {\n    this.fetchOptionsCancel();\n  },\n  methods: {\n    onOptionSelected(): void {\n      this.$emit('input', new CustomEvent('input', {\n        detail: this.localValue,\n      }));\n      \n      this.$emit('change', new CustomEvent('change', {\n        detail: this.localValue,\n      }));\n\n      if (this.shown === false) {\n        return;\n      }\n\n      this.adjustDropdown();\n\n      if (\n        this.configuration.closeOnSelect === true\n        // If `closeOnSelect`  is not set hide the dropdown only when is not\n        // multiple\n        || (this.configuration.closeOnSelect === undefined\n          && !this.configuration.multiple)\n      ) {\n        this.hideDropdown();\n\n        this.focusDropdownTrigger();\n      }\n    },\n    beforeHideHandler(): void {\n      this.$emit('before-hide');\n\n      if (\n        this.configuration.selectOnClose\n        && !isEqual(this.localValue, this.activeOption?.value)\n      ) {\n        this.selectOptionFromActiveOption();\n      }\n    },\n    shownHandler(): void {\n      this.$emit('shown');\n\n      this.shown = true;\n    },\n    hiddenHandler(): void {\n      this.$emit('hidden');\n\n      this.shown = false;\n\n      if (this.clearSearchOnClose) {\n        this.searchQuery = undefined;\n      }\n    },\n    beforeShowHandler(): void {\n      this.$emit('before-show');\n\n      this.initActiveOption();\n\n      if (this.canFetchOptions) {\n        this.doFetchOptions();\n      }\n    },\n    mousedownHandler(e: MouseEvent): void {\n      this.$emit('mousedown', e);\n\n      if (this.configuration.toggleOnClick) {\n        // If it has as search box I need to prevent default to ensure the search\n        // box keep focused\n        if (this.showSearchInput && this.shown === false) {\n          e.preventDefault();\n        }\n\n        this.toggleDropdown();\n      }\n    },\n    focusHandler(e: FocusEvent): void {\n      this.$emit('focus', e);\n\n      if (this.configuration.toggleOnFocus) {\n        this.throttledShowDropdown();\n      }\n    },\n    blurOnChildHandler(e: FocusEvent): void {\n      const target = e.target as HTMLButtonElement | HTMLInputElement;\n      const relatedTarget = e.relatedTarget as HTMLElement | EventTarget;\n      const relatedTargetDataset: Data | undefined = relatedTarget instanceof HTMLElement\n        ? relatedTarget.dataset\n        : undefined;\n\n      if (\n        target.dataset.richSelectFocusable !== undefined\n        && relatedTargetDataset\n        && relatedTargetDataset.richSelectFocusable === undefined\n      ) {\n        target.focus();\n      }\n    },\n    blurHandler(e: FocusEvent): void {\n      this.$emit('blur', e);\n\n      this.hideDropdown();\n    },\n  },\n});\n</script>\n"
  },
  {
    "path": "src/components/TSelect/TSelectOption.vue",
    "content": "<template>\n  <optgroup\n    v-if=\"hasChildren\"\n    :data-value=\"option.value !== undefined ? String(option.value) : undefined\"\n    :label=\"option.text !== undefined ? String(option.text) : undefined\"\n    :disabled=\"!! option.disabled\"\n  >\n    <t-select-option\n      v-for=\"(childrenOption, index) in option.children\"\n      :key=\"`${childrenOption.value}-${childrenOption.text}-${index}`\"\n      :option=\"childrenOption\"\n    />\n  </optgroup>\n  <option\n    v-else\n    :value=\"option.value === null ? undefined : option.value\"\n    :disabled=\"!! option.disabled\"\n    v-text=\"option.text\"\n  />\n</template>\n\n<script lang=\"ts\">\nimport { NormalizedOption } from '@variantjs/core';\nimport { defineComponent, PropType } from 'vue';\n\n// @vue/component\nexport default defineComponent({\n  name: 'TSelectOption',\n  compatConfig: {\n    MODE: 3,\n  },\n  props: {\n    option: {\n      type: [Object] as PropType<NormalizedOption>,\n      required: true,\n    },\n  },\n  computed: {\n    hasChildren(): boolean {\n      return this.option.children !== undefined && this.option.children.length > 0;\n    },\n  },\n});\n</script>\n"
  },
  {
    "path": "src/components/TSelect.vue",
    "content": "<template>\n  <select\n    v-model=\"localValue\"\n    :multiple=\"configuration.multiple\"\n    v-bind=\"attributes\"\n  >\n    <t-select-option\n      v-for=\"(option, index) in normalizedOptions\"\n      :key=\"`${option.value}-${index}`\"\n      :option=\"option\"\n    />\n  </select>\n</template>\n\n<script lang=\"ts\">\nimport {\n  InputOptions, NormalizedOption, NormalizedOptions, TSelectConfig,\n} from '@variantjs/core';\nimport { defineComponent, PropType, computed } from 'vue';\nimport { Truthy, TSelectOptions, TSelectValue } from '../types';\nimport TSelectOption from './TSelect/TSelectOption.vue';\nimport useMulipleableVModel from '../use/useMulipleableVModel';\nimport useMultioptions from '../use/useMultioptions';\nimport useConfiguration from '../use/useConfiguration';\nimport { getVariantProps } from '../utils/getVariantProps';\n\n// @vue/component\nexport default defineComponent({\n  name: 'TSelect',\n  compatConfig: {\n    MODE: 3,\n  },\n  components: {\n    TSelectOption,\n  },\n  props: {\n    ...getVariantProps<TSelectOptions>(),\n    modelValue: {\n      type: [String, Number, Boolean, Array, Object, Date, Function, Symbol] as PropType<TSelectValue>,\n      default: undefined,\n    },\n    options: {\n      type: [Array, Object] as PropType<InputOptions | NormalizedOption[] | NormalizedOptions>,\n      default: undefined,\n    },\n    normalizeOptions: {\n      type: Boolean,\n      default: true,\n    },\n    valueAttribute: {\n      type: String,\n      default: undefined,\n    },\n    textAttribute: {\n      type: String,\n      default: undefined,\n    },\n    multiple: {\n      type: [String, Boolean] as PropType<Truthy>,\n      default: false,\n    },\n  },\n  setup(props) {\n    const { configuration, attributes } = useConfiguration<TSelectOptions>(TSelectConfig);\n    const { localValue } = useMulipleableVModel(props, 'modelValue', configuration);\n\n    const {\n      normalizedOptions,\n    } = useMultioptions(\n      computed(() => configuration.options as InputOptions | undefined),\n      computed(() => configuration.textAttribute),\n      computed(() => configuration.valueAttribute),\n      computed(() => configuration.normalizeOptions!),\n    );\n\n    return {\n      localValue: localValue as any,\n      configuration,\n      attributes,\n      normalizedOptions,\n    };\n  },\n});\n</script>\n"
  },
  {
    "path": "src/components/TTag.vue",
    "content": "<template>\n  <component\n    :is=\"configuration.tagName\"\n    v-bind=\"attributes\"\n  >\n    <slot :configuration=\"configuration\">\n      {{ configuration.text }}\n    </slot>\n  </component>\n</template>\n\n<script lang=\"ts\">\nimport { TTagConfig } from '@variantjs/core';\nimport { defineComponent } from 'vue';\nimport { TTagOptions } from '../types';\nimport useConfiguration from '../use/useConfiguration';\nimport { getVariantProps } from '../utils/getVariantProps';\n\n// @vue/component\nexport default defineComponent({\n  name: 'TTag',\n  compatConfig: {\n    MODE: 3,\n  },\n  props: {\n    ...getVariantProps<TTagOptions>(),\n    tagName: {\n      type: String,\n      default: 'div',\n    },\n    text: {\n      type: String,\n      default: undefined,\n    },\n  },\n  setup() {\n    const { configuration, attributes } = useConfiguration<TTagOptions>(TTagConfig);\n\n    return { configuration, attributes };\n  },\n});\n\n</script>\n"
  },
  {
    "path": "src/components/TTextarea.vue",
    "content": "<template>\n  <textarea\n    v-if=\"usesVModel\"\n    v-model=\"localValue\"\n    v-bind=\"attributes\"\n  />\n  <textarea\n    v-else\n    v-bind=\"attributes\"\n  />\n</template>\n\n<script lang=\"ts\">\nimport { TTextareaConfig } from '@variantjs/core';\nimport { defineComponent, PropType, getCurrentInstance } from 'vue';\nimport { TTextareaOptions, TTextareaValue } from '../types';\nimport { getVariantProps } from '../utils/getVariantProps';\nimport useVModel from '../use/useVModel';\nimport useConfiguration from '../use/useConfiguration';\n\nexport default defineComponent({\n  name: 'TTextarea',\n  compatConfig: {\n    MODE: 3,\n  },\n  props: {\n    ...getVariantProps<TTextareaOptions>(),\n    modelValue: {\n      type: [String, Number] as PropType<TTextareaValue>,\n      default: undefined,\n    },\n  },\n  setup(props) {\n    const vm = getCurrentInstance();\n\n    const definedProps = vm!.vnode.props;\n\n    const usesVModel = definedProps && definedProps.modelValue !== undefined;\n\n    const localValue = useVModel(props, 'modelValue');\n    const { configuration, attributes } = useConfiguration<TTextareaOptions>(TTextareaConfig);\n\n    return {\n      usesVModel, localValue, configuration, attributes,\n    };\n  },\n});\n</script>\n"
  },
  {
    "path": "src/components/TToggle.vue",
    "content": "<template>\n  <button\n    type=\"button\"\n    role=\"checkbox\"\n    :aria-checked=\"isChecked ? 'true' : 'false'\"\n    :class=\"classes.wrapper\"\n    :disabled=\"configuration.disabled\"\n    @click=\"toggle\"\n  >\n    <input\n      v-if=\"!isMultiple || isChecked\"\n      :value=\"inputValue\"\n      type=\"hidden\"\n      :name=\"configuration.name\"\n      :disabled=\"configuration.disabled\"\n    >\n    <span\n      aria-hidden=\"true\"\n      :class=\"configuration.classesList?.uncheckedPlaceholder\"\n    >\n      <slot\n        name=\"unchecked\"\n        :value=\"inputValue\"\n        :is-checked=\"isChecked\"\n      >{{ configuration.uncheckedPlaceholder }}</slot>\n    </span>\n\n    <span\n      aria-hidden=\"true\"\n      :class=\"configuration.classesList?.checkedPlaceholder\"\n    >\n      <slot\n        name=\"checked\"\n        :value=\"inputValue\"\n        :is-checked=\"isChecked\"\n      >{{ configuration.checkedPlaceholder }}</slot>\n    </span>\n    <span\n      aria-hidden=\"true\"\n      :class=\"classes.button\"\n    >\n      <slot\n        :value=\"inputValue\"\n        :is-checked=\"isChecked\"\n      />\n    </span>\n  </button>\n</template>\n\n<script lang=\"ts\">\nimport {\n  defineComponent, PropType, computed, ref, watch, getCurrentInstance,\n} from 'vue';\nimport {\n  TToggleConfig,\n  TToggleClassesKeys,\n  TToggleClassesValidKeys,\n  isEqual,\n  hasProperty,\n  substractFromArray,\n  addToArray,\n} from '@variantjs/core';\nimport useConfigurationWithClassesList from '../use/useConfigurationWithClassesList';\nimport { getVariantPropsWithClassesList } from '../utils/getVariantProps';\nimport { TToggleOptions, TToggleValue } from '../types/components/t-toggle';\n\n// @vue/component\nexport default defineComponent({\n  name: 'TToggle',\n  compatConfig: {\n    MODE: 3,\n  },\n  props: {\n    ...getVariantPropsWithClassesList<TToggleOptions, TToggleClassesValidKeys>(),\n    name: {\n      type: String,\n      default: undefined,\n    },\n    modelValue: {\n      type: [String, Number, Boolean, Array, Object, Date, Function, Symbol] as PropType<TToggleValue>,\n      default: undefined,\n    },\n    value: {\n      type: [String, Number, Boolean, Array, Object, Date, Function, Symbol] as PropType<TToggleValue>,\n      default: true,\n    },\n    uncheckedValue: {\n      type: [String, Number, Boolean, Array, Object, Date, Function, Symbol] as PropType<TToggleValue>,\n      default: false,\n    },\n    checked: {\n      type: Boolean,\n      default: undefined,\n    },\n    disabled: {\n      type: Boolean,\n      default: undefined,\n    },\n    checkedPlaceholder: {\n      type: String,\n      default: undefined,\n    },\n    uncheckedPlaceholder: {\n      type: String,\n      default: undefined,\n    },\n  },\n  emits: {\n    // eslint-disable-next-line @typescript-eslint/no-unused-vars\n    'update:checked': (isChecked: boolean) => true,\n    // eslint-disable-next-line @typescript-eslint/no-unused-vars\n    'update:modelValue': (value: TToggleValue) => true,\n  },\n  setup(props, { emit }) {\n    const { configuration, attributes } = useConfigurationWithClassesList<TToggleOptions>(TToggleConfig, TToggleClassesKeys);\n\n    const vm = getCurrentInstance();\n\n    const getInitialValue = (): TToggleValue => {\n      const modelValueIsDefined = hasProperty(vm!.vnode.props, 'modelValue');\n\n      if (modelValueIsDefined) {\n        return props.modelValue;\n      }\n\n      if (configuration.checked === true) {\n        return configuration.value;\n      }\n\n      return configuration.uncheckedValue;\n    };\n\n    const localValue = ref<TToggleValue>(getInitialValue());\n\n    const isMultiple = computed<boolean>(() => Array.isArray(localValue.value));\n\n    const isChecked = computed<boolean>(() => {\n      if (isMultiple.value) {\n        return (localValue.value as TToggleValue[]).some((value) => isEqual(value, configuration.value));\n      }\n\n      return isEqual(localValue.value, configuration.value);\n    });\n\n    const inputValue = computed(() => {\n      if (isChecked.value) {\n        return configuration.value;\n      }\n\n      return configuration.uncheckedValue;\n    });\n\n    const check = () => {\n      if (isMultiple.value) {\n        localValue.value = addToArray(localValue.value, configuration.value);\n      } else {\n        localValue.value = configuration.value;\n      }\n    };\n\n    const uncheck = () => {\n      if (isMultiple.value) {\n        localValue.value = substractFromArray(localValue.value, configuration.value);\n      } else {\n        localValue.value = configuration.uncheckedValue;\n      }\n    };\n\n    const toggle = () => {\n      if (isChecked.value) {\n        uncheck();\n      } else {\n        check();\n      }\n    };\n\n    watch(localValue, (newValue: TToggleValue) => {\n      emit('update:modelValue', newValue);\n    });\n\n    watch(isChecked, (newIsChecked: boolean) => {\n      emit('update:checked', newIsChecked);\n    });\n\n    watch(() => props.modelValue, (newModelValue: TToggleValue) => {\n      localValue.value = newModelValue;\n    });\n\n    watch(() => configuration.checked, (newChecked: boolean | undefined) => {\n      if (newChecked) {\n        check();\n      } else {\n        uncheck();\n      }\n    });\n\n    const classes = computed(() => {\n      if (configuration.disabled) {\n        return {\n          wrapper: isChecked.value ? configuration.classesList!.wrapperCheckedDisabled : configuration.classesList!.wrapperDisabled,\n          button: isChecked.value ? configuration.classesList!.buttonChecked : configuration.classesList!.button,\n        };\n      }\n\n      return {\n        wrapper: isChecked.value ? configuration.classesList!.wrapperChecked : configuration.classesList!.wrapper,\n        button: isChecked.value ? configuration.classesList!.buttonChecked : configuration.classesList!.button,\n      };\n    });\n\n    return {\n      configuration,\n      attributes,\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      localValue: localValue as any,\n      isChecked,\n      isMultiple,\n      classes,\n      inputValue,\n      toggle,\n    };\n  },\n});\n\n</script>\n"
  },
  {
    "path": "src/components/misc/TextPlaceholder.vue",
    "content": "<template>\n  <span :class=\"className\">\n    <slot>\n      <template v-if=\"placeholder !== undefined\">{{ placeholder }}</template>\n      <template v-else>&nbsp;</template>\n    </slot>\n  </span>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\nimport useInjectsClassesListClass from '../../use/useInjectsClassesListClass';\n\nexport default defineComponent({\n  name: 'TextPlaceholder',\n  compatConfig: {\n    MODE: 3,\n  },\n  props: {\n    classProperty: {\n      type: String,\n      default: 'placeholder',\n    },\n    placeholder: {\n      type: String,\n      default: undefined,\n    },\n  },\n  setup(props) {\n    const className = useInjectsClassesListClass(props.classProperty);\n\n    return { className };\n  },\n});\n</script>\n"
  },
  {
    "path": "src/components/misc/Transitionable.vue",
    "content": "<template>\n  <transition\n    :enter-active-class=\"classesList?.enterActiveClass\"\n    :enter-from-class=\"classesList?.enterFromClass\"\n    :enter-to-class=\"classesList?.enterToClass\"\n    :leave-active-class=\"classesList?.leaveActiveClass\"\n    :leave-from-class=\"classesList?.leaveFromClass\"\n    :leave-to-class=\"classesList?.leaveToClass\"\n    :css=\"enabled\"\n  >\n    <slot />\n  </transition>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\n// @vue/component\nexport default defineComponent({\n  name: 'Transitionable',\n  compatConfig: {\n    MODE: 3,\n  },\n  props: {\n    classesList: {\n      type: Object,\n      default: () => ({}),\n    },\n    enabled: {\n      type: Boolean,\n      default: true,\n    },\n  },\n});\n</script>\n"
  },
  {
    "path": "src/development/About.vue",
    "content": "<template>\n  <t-card>\n    <template #header>\n      <h1>VariantJS</h1>\n    </template>\n\n    <p>Development playground used for testing purposes.</p>\n\n    <template #footer>\n      <p>Made by love by <a href=\"\">@alfonsobries</a></p>\n    </template>\n  </t-card>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\nimport TCard from '../components/TCard.vue';\n\nexport default defineComponent({\n  name: 'About',\n  components: {\n    TCard,\n  },\n});\n</script>\n"
  },
  {
    "path": "src/development/Alert.vue",
    "content": "<template>\n  <t-card>\n    <template #header>\n      <h1>Alert</h1>\n    </template>\n\n    <TInputGroup\n      label=\"Regular alert\"\n      class=\"mb-4\"\n    >\n      <t-alert>\n        Lorem, ipsum dolor sit amet consectetur adipisicing elit. Obcaecati ipsam necessitatibus deserunt quas dolorum at laboriosam, expedita eveniet facere excepturi non hic esse! Facere, illum qui? Minus iste porro quidem!\n      </t-alert>\n    </TInputGroup>\n\n    <TInputGroup\n      label=\"Syncs with the show v-model\"\n      class=\"mb-4\"\n    >\n      <div>\n        <t-checkbox v-model=\"show\" />\n      </div>\n\n      <t-alert\n        v-model:show=\"show\"\n        class=\"mt-2\"\n        :close-icon=\"customCloseIcon\"\n      >\n        Lorem, ipsum dolor sit amet consectetur adipisicing elit. Obcaecati ipsam necessitatibus deserunt quas dolorum at laboriosam, expedita eveniet facere excepturi non hic esse! Facere, illum qui? Minus iste porro quidem!\n      </t-alert>\n    </TInputGroup>\n  </t-card>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nimport TCheckbox from '../components/TCheckbox.vue';\nimport TCard from '../components/TCard.vue';\nimport TAlert from '../components/TAlert.vue';\nimport TInputGroup from '../components/TInputGroup.vue';\n\nexport default defineComponent({\n  name: 'App',\n  components: {\n    TCheckbox,\n    TCard,\n    TAlert,\n    TInputGroup,\n  },\n  data() {\n    return {\n      show: true,\n      customCloseIcon: `<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\">\n  <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z\" />\n</svg>`,\n    };\n  },\n  mounted() {},\n});\n</script>\n"
  },
  {
    "path": "src/development/App.vue",
    "content": "<template>\n  <div class=\"pb-36\">\n    <div class=\"relative z-10 p-4 sm:hidden\">\n      <t-dropdown ref=\"dropdown\">\n        <template #trigger>\n          Menú\n        </template>\n\n        <div class=\"p-4\">\n          <app-menu />\n        </div>\n      </t-dropdown>\n    </div>\n\n    <div class=\"flex max-w-2xl mx-auto mb-10 space-x-4 sm:mt-10\">\n      <div>\n        <app-menu class=\"hidden sm:block\" />\n      </div>\n\n      <div class=\"flex flex-col items-center flex-grow\">\n        <router-view />\n      </div>\n    </div>\n  </div>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\nimport AppMenu from './AppMenu.vue';\nimport TDropdown from '../components/TDropdown.vue';\n\nexport default defineComponent({\n  name: 'App',\n  components: { AppMenu, TDropdown },\n  watch: {\n    $route() {\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      (this.$refs.dropdown as any).doHide();\n    },\n  },\n});\n</script>\n"
  },
  {
    "path": "src/development/AppMenu.vue",
    "content": "<template>\n  <div class=\"flex flex-col space-y-3\">\n    <t-button to=\"/\">\n      Home\n    </t-button>\n    <t-button to=\"/theme\">\n      Theme\n    </t-button>\n    <t-button to=\"/attributes\">\n      Attributes\n    </t-button>\n    <t-button to=\"/checkbox\">\n      Checkbox\n    </t-button>\n    <t-button to=\"/options\">\n      Options\n    </t-button>\n    <t-button to=\"/multioptions\">\n      MultiOptions\n    </t-button>\n    <t-button to=\"/dropdown\">\n      Dropdown\n    </t-button>\n    <t-button to=\"/alert\">\n      Alert\n    </t-button>\n    <t-button to=\"/rich-select\">\n      Rich Select\n    </t-button>\n    <t-button to=\"/modal\">\n      Modal\n    </t-button>\n    <t-button to=\"/dialog\">\n      Dialog\n    </t-button>\n    <t-button to=\"/about\">\n      About\n    </t-button>\n  </div>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\nimport TButton from '../components/TButton.vue';\n\nexport default defineComponent({\n  name: 'AppMenu',\n  components: {\n    TButton,\n  },\n});\n</script>\n"
  },
  {
    "path": "src/development/Attributes.vue",
    "content": "<template>\n  <t-card\n    class=\"w-full\"\n    header=\"Attributes\"\n  >\n    <div class=\"grid grid-cols-1 gap-6\">\n      <p>Gets the same placeholder attribute from different sources</p>\n\n      <p>From the attribute</p>\n      <t-input\n        v-model=\"model\"\n        placeholder=\"Defined on the attribute\"\n      />\n\n      <p>Placeholder from the value (v-model) of input above</p>\n      <t-input :placeholder=\"model\" />\n\n      <p>From the attribute (to ensure is overriden)</p>\n      <t-input\n        placeholder=\"Defined on the attribute (overrides the variant)\"\n        variant=\"alt\"\n      />\n\n      <p>Placeholder on the configuration</p>\n      <t-input />\n\n      <p>Placeholder on the variant</p>\n      <t-input variant=\"alt\" />\n    </div>\n  </t-card>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent, provide } from 'vue';\nimport TInput from '../components/TInput.vue';\nimport TCard from '../components/TCard.vue';\n\nexport default defineComponent({\n  name: 'Attributes',\n  components: {\n    TInput,\n    TCard,\n  },\n  setup() {\n    provide('configuration', {\n      TInput: {\n        placeholder: 'Comes from the config',\n        variants: {\n          alt: {\n            placeholder: 'From \"alt\" variant',\n          },\n        },\n      },\n    });\n  },\n  data() {\n    return {\n      model: '',\n    };\n  },\n\n});\n</script>\n"
  },
  {
    "path": "src/development/Check.vue",
    "content": "<template>\n  <t-card header=\"Options\">\n    <TInputGroup\n      label=\"Toggle/Checkbox model sync \"\n      class=\"mb-4\"\n    >\n      <t-toggle v-model=\"selected\" />\n      <t-checkbox v-model=\"selected\" />\n      <input\n        v-model=\"selected\"\n        type=\"checkbox\"\n      >\n\n      <p>Value: {{ selected }}</p>\n    </TInputGroup>\n    <TInputGroup\n      label=\"No v-model\"\n      class=\"mb-4\"\n    >\n      <t-toggle />\n      <t-checkbox />\n    </TInputGroup>\n\n    <TInputGroup\n      label=\"Checked attribute\"\n      class=\"mb-4\"\n    >\n      <t-toggle checked />\n      <t-checkbox checked />\n    </TInputGroup>\n\n    <TInputGroup\n      label=\"Custom value\"\n      class=\"mb-4\"\n    >\n      <t-toggle\n        v-model=\"accepted\"\n        checked\n        value=\"accepted\"\n        unchecked-value=\"notAccepted\"\n      />\n      <t-checkbox\n        v-model=\"accepted\"\n        checked\n        value=\"accepted\"\n        unchecked-value=\"notAccepted\"\n      />\n\n      <p>Value: {{ accepted }}</p>\n    </TInputGroup>\n\n    <TInputGroup\n      label=\"Checked attribute sync\"\n      class=\"mb-4\"\n    >\n      <t-toggle v-model:checked=\"checked\" />\n\n      <input\n        v-model=\"checked\"\n        type=\"checkbox\"\n      >\n    </TInputGroup>\n\n    <TInputGroup\n      label=\"Multiple\"\n      class=\"mb-4\"\n    >\n      <div class=\"flex space-x-2\">\n        <t-toggle\n          v-model=\"multiple\"\n          checked\n          name=\"test\"\n          value=\"a\"\n        />\n        <t-toggle\n          v-model=\"multiple\"\n          checked\n          name=\"test\"\n          value=\"b\"\n        />\n        <t-toggle\n          v-model=\"multiple\"\n          checked\n          name=\"test\"\n          value=\"c\"\n        />\n\n        <p>Value {{ multiple }}</p>\n      </div>\n\n      <div class=\"flex space-x-2\">\n        <t-checkbox\n          v-model=\"multiple\"\n          checked\n          value=\"a\"\n        />\n        <t-checkbox\n          v-model=\"multiple\"\n          checked\n          value=\"b\"\n        />\n        <t-checkbox\n          v-model=\"multiple\"\n          checked\n          value=\"c\"\n        />\n\n        <p>Value {{ multiple }}</p>\n      </div>\n      <div class=\"flex space-x-2\">\n        <input\n          v-model=\"multiple\"\n          type=\"checkbox\"\n          value=\"a\"\n        >\n        <input\n          v-model=\"multiple\"\n          type=\"checkbox\"\n          value=\"b\"\n        >\n        <input\n          v-model=\"multiple\"\n          type=\"checkbox\"\n          value=\"c\"\n        >\n\n        <p>Value {{ multiple }}</p>\n      </div>\n    </TInputGroup>\n\n    <TInputGroup\n      label=\"Toggle placeholders\"\n      class=\"mb-4\"\n    >\n      <t-toggle\n        checked-placeholder=\"AM\"\n        unchecked-placeholder=\"PM\"\n      />\n    </TInputGroup>\n    <TInputGroup\n      label=\"Disabled \"\n      class=\"mb-4\"\n    >\n      <t-toggle\n        disabled\n      />\n    </TInputGroup>\n  </t-card>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\nimport TToggle from '../components/TToggle.vue';\nimport TCheckbox from '../components/TCheckbox.vue';\nimport TCard from '../components/TCard.vue';\nimport TInputGroup from '../components/TInputGroup.vue';\n\nexport default defineComponent({\n  name: 'Check',\n  components: {\n    TCheckbox,\n    TToggle,\n    TCard,\n    TInputGroup,\n  },\n  data() {\n    return {\n      accepted: 'accepted',\n      selected: true,\n      multiple: ['b'],\n      checked: false,\n    };\n  },\n\n});\n</script>\n"
  },
  {
    "path": "src/development/Dialog.vue",
    "content": "<template>\n  <t-card class=\"w-full\">\n    <template #header>\n      <h1>Dialog</h1>\n    </template>\n\n    <TInputGroup\n      label=\"Dialog types\"\n      class=\"mb-4\"\n    >\n      <div class=\"flex mb-2 space-x-3\">\n        <label\n          for=\"alert\"\n          class=\"flex items-center space-x-1\"\n        >\n          <t-radio\n            id=\"alert\"\n            v-model=\"dialogType\"\n            value=\"alert\"\n          />\n          <span>Alert</span>\n        </label>\n        <label\n          for=\"confirm\"\n          class=\"flex items-center space-x-1\"\n        >\n          <t-radio\n            id=\"confirm\"\n            v-model=\"dialogType\"\n            value=\"confirm\"\n          />\n          <span>Confirm</span>\n        </label>\n        <label\n          for=\"prompt\"\n          class=\"flex items-center space-x-1\"\n        >\n          <t-radio\n            id=\"prompt\"\n            v-model=\"dialogType\"\n            value=\"prompt\"\n          />\n          <span>Prompt</span>\n        </label>\n      </div>\n\n      <div class=\"flex mb-2 space-x-3\">\n        <label\n          for=\"success\"\n          class=\"flex items-center space-x-1\"\n        >\n          <t-radio\n            id=\"success\"\n            v-model=\"dialogIcon\"\n            value=\"success\"\n          />\n          <span>success</span>\n        </label>\n        <label\n          for=\"error\"\n          class=\"flex items-center space-x-1\"\n        >\n          <t-radio\n            id=\"error\"\n            v-model=\"dialogIcon\"\n            value=\"error\"\n          />\n          <span>Error</span>\n        </label>\n        <label\n          for=\"warning\"\n          class=\"flex items-center space-x-1\"\n        >\n          <t-radio\n            id=\"warning\"\n            v-model=\"dialogIcon\"\n            value=\"warning\"\n          />\n          <span>Warning</span>\n        </label>\n        <label\n          for=\"info\"\n          class=\"flex items-center space-x-1\"\n        >\n          <t-radio\n            id=\"info\"\n            v-model=\"dialogIcon\"\n            value=\"info\"\n          />\n          <span>Info</span>\n        </label>\n        <label\n          for=\"question\"\n          class=\"flex items-center space-x-1\"\n        >\n          <t-radio\n            id=\"question\"\n            v-model=\"dialogIcon\"\n            value=\"question\"\n          />\n          <span>Question</span>\n        </label>\n      </div>\n    </TInputGroup>\n\n    <TInputGroup\n      label=\"Open with dialog name\"\n      class=\"mb-4\"\n    >\n      <t-dialog\n        name=\"my-dialog\"\n        title=\"Are you sure?\"\n        text=\"This action cannot be undone\"\n        :icon=\"dialogIcon\"\n        :type=\"dialogType\"\n      />\n\n      <div class=\"flex space-x-2\">\n        <t-button\n          @click=\"showNamedDialog('my-dialog')\"\n        >\n          Show {{ dialogType }} dialog\n        </t-button>\n      </div>\n    </TInputGroup>\n\n    <TInputGroup\n      label=\"Prompt\"\n      class=\"mb-4\"\n    >\n      <t-dialog\n        icon=\"question\"\n        type=\"prompt\"\n        input-type=\"text\"\n        input-value=\"A\"\n        title=\"This is a restricted section\"\n        text=\"Whats is your secret word?\"\n        name=\"input-dialog\"\n      />\n      <div class=\"flex space-x-2\">\n        <t-button\n          @click=\"showNamedDialog('input-dialog')\"\n        >\n          Show dialog with text input\n        </t-button>\n      </div>\n    </TInputGroup>\n\n    <TInputGroup\n      label=\"Prompt with custom input\"\n      class=\"mb-4\"\n    >\n      <t-dialog\n        icon=\"question\"\n        type=\"prompt\"\n        input-type=\"text\"\n        input-value=\"A\"\n        title=\"This is a restricted section\"\n        text=\"Whats is your secret word?\"\n        name=\"custom-input-dialog\"\n      >\n        <template #input=\"{ setInputValue }\">\n          <TSelect\n            :options=\"['A', 'B', 'C']\"\n            @change=\"setInputValue(($event as any).target.value)\"\n          />\n        </template>\n      </t-dialog>\n      <div class=\"flex space-x-2\">\n        <t-button\n          @click=\"showNamedDialog('custom-input-dialog')\"\n        >\n          Show witch custom select input\n        </t-button>\n      </div>\n    </TInputGroup>\n\n    <TInputGroup\n      label=\"Input with a validator\"\n      class=\"mb-4\"\n    >\n      <t-dialog\n        icon=\"question\"\n        type=\"prompt\"\n        title=\"Secret word?\"\n        text=\"Pass a word that is between 5 and 10 chars\"\n        name=\"input-with-validator\"\n        :input-validator=\"inputValidator\"\n      />\n\n      <div class=\"flex space-x-2\">\n        <t-button\n          @click=\"showNamedDialog('input-with-validator')\"\n        >\n          Show input\n        </t-button>\n      </div>\n    </TInputGroup>\n\n    <TInputGroup\n      label=\"Alert with failing promise\"\n      class=\"mb-4\"\n    >\n      <t-dialog\n        icon=\"question\"\n        type=\"alert\"\n        title=\"Delete?\"\n        text=\"This action cannot be undone\"\n        name=\"promise-alert\"\n        :pre-confirm=\"failingAlertPromise\"\n      />\n\n      <div class=\"flex space-x-2\">\n        <t-button\n          @click=\"showNamedDialog('promise-alert')\"\n        >\n          Show alert that will fail\n        </t-button>\n      </div>\n    </TInputGroup>\n\n    <TInputGroup\n      label=\"Alert with success promise\"\n      class=\"mb-4\"\n    >\n      <t-dialog\n        icon=\"question\"\n        type=\"alert\"\n        title=\"Delete?\"\n        text=\"This action cannot be undone\"\n        name=\"promise-alert-succeed\"\n        :pre-confirm=\"successAlertResponse\"\n      />\n\n      <div class=\"flex space-x-2\">\n        <t-button\n          @click=\"showNamedDialog('promise-alert-succeed')\"\n        >\n          Show alert that will succeed\n        </t-button>\n      </div>\n    </TInputGroup>\n\n    <TInputGroup\n      label=\"Syncs show property\"\n      class=\"mb-4\"\n    >\n      <div>\n        <t-checkbox v-model=\"show\" />\n      </div>\n\n      <t-dialog v-model=\"show\" />\n    </TInputGroup>\n\n    <TInputGroup\n      label=\"Only closable trough the custom button inside\"\n      class=\"mb-4\"\n    >\n      <t-button @click=\"$dialog.show('notClosable')\">\n        Show dialog\n      </t-button>\n\n      <t-dialog\n        name=\"notClosable\"\n        :esc-to-close=\"false\"\n        :click-to-close=\"false\"\n      >\n        <template #default=\"{ hide }\">\n          <t-button @click=\"() => hide()\">\n            Close this\n          </t-button>\n        </template>\n      </t-dialog>\n    </TInputGroup>\n\n    <TInputGroup\n      label=\"Open alert programatically\"\n      class=\"mb-4\"\n    >\n      <t-button @click=\"programaticAlert\">\n        Show alert\n      </t-button>\n      <t-button @click=\"programaticAlert2\">\n        Show alert alt\n      </t-button>\n      <t-button @click=\"programaticFailingAlert\">\n        Show failing alert\n      </t-button>\n    </TInputGroup>\n  </t-card>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nimport { Data, DialogIcon, DialogType } from '@variantjs/core';\nimport TCheckbox from '../components/TCheckbox.vue';\nimport TButton from '../components/TButton.vue';\nimport TCard from '../components/TCard.vue';\nimport TDialog from '../components/TDialog.vue';\nimport TSelect from '../components/TSelect.vue';\nimport TRadio from '../components/TRadio.vue';\nimport TInputGroup from '../components/TInputGroup.vue';\n\nconst failingAlertPromise = () => new Promise((resolve, reject) => {\n  setTimeout(() => {\n    reject(new Error('Failed to delete'));\n  }, 1000);\n});\n\nconst successAlertResponse = () => new Promise((resolve) => {\n  setTimeout(() => {\n    resolve({\n      foo: 'bar',\n    });\n  }, 1000);\n});\n\nexport default defineComponent({\n  name: 'App',\n  components: {\n    TButton,\n    TCheckbox,\n    TCard,\n    TDialog,\n    TSelect,\n    TInputGroup,\n    TRadio,\n  },\n  data() {\n    return {\n      dialogIcon: 'success' as DialogIcon,\n      dialogType: 'alert' as DialogType,\n      show: false,\n      email: 'alfonso@variantjs.com',\n      name: 'Alfonso',\n      user: {} as Data,\n      failingAlertPromise,\n      successAlertResponse,\n    };\n  },\n  methods: {\n    inputValidator(input: any) {\n      const isProperLength = String(input).length >= 5 && String(input).length <= 10;\n\n      if (!isProperLength) {\n        return `Your word is ${String(input).length} chars length`;\n      }\n\n      return null;\n    },\n    programaticAlert() {\n      this.$dialog.alert('Whatever').then((result) => {\n        console.log('result', result);\n      }).catch((error) => {\n        console.log('error', error);\n      });\n    },\n    programaticAlert2() {\n      this.$confirm('Whatever').then((result) => {\n        console.log('result', result);\n      }).catch((error) => {\n        console.log('error', error);\n      });\n    },\n    programaticFailingAlert() {\n      this.$dialog.alert({\n        title: 'Will fail',\n        icon: DialogIcon.Error,\n        preConfirm: failingAlertPromise,\n      }).then((result) => {\n        console.log('result', result);\n      }).catch((error) => {\n        console.log('error', error);\n      });\n    },\n    async showNamedDialog(name: string) {\n      this.$dialog.show(name)\n        .then((result) => {\n          console.log('result', result);\n        }).catch((error) => {\n          console.log('error', error);\n        });\n    },\n    onBeforeShow({ params, cancel }: { params: { email: string }, cancel: () => void }) {\n      const { email } = params;\n      if (email === 'cancel') {\n        cancel();\n        return;\n      }\n\n      this.user = {\n        email,\n      };\n    },\n    onBeforeHide({ cancel }: { cancel: () => void }) {\n      if (this.email === 'cancel') {\n        cancel();\n      }\n    },\n  },\n});\n</script>\n"
  },
  {
    "path": "src/development/Dropdown.vue",
    "content": "<template>\n  <t-card>\n    <template #header>\n      <h1>Dropdown</h1>\n    </template>\n\n    <TInputGroup\n      label=\"Toggle on focus\"\n      class=\"mb-4\"\n    >\n      <t-dropdown\n        text=\"Toggle on focus\"\n        toggle-on-focus\n        :toggle-on-click=\"false\"\n      >\n        <template #default=\"{ hide }\">\n          <div>\n            <button\n              class=\"block w-full px-4 py-2 text-sm leading-5 text-gray-700 transition duration-150 ease-in-out hover:bg-gray-100 focus:outline-none focus:bg-gray-100\"\n              role=\"menuitem\"\n            >\n              Your Profile\n            </button>\n            <button\n              class=\"block w-full px-4 py-2 text-sm leading-5 text-gray-700 transition duration-150 ease-in-out hover:bg-gray-100 focus:outline-none focus:bg-gray-100\"\n              role=\"menuitem\"\n            >\n              Settings\n            </button>\n\n            <button\n              class=\"block w-full px-4 py-2 text-sm leading-5 text-red-500 transition duration-150 ease-in-out border-t hover:bg-gray-100 focus:outline-none focus:bg-gray-100\"\n              @click=\"hide\"\n            >\n              Close me\n            </button>\n          </div>\n        </template>\n      </t-dropdown>\n\n      <t-dropdown\n        class=\"mt-2\"\n        text=\"Toggle on focus without focusable elements\"\n        toggle-on-focus\n        :toggle-on-click=\"false\"\n      >\n        <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Eius dolores nesciunt rem iure blanditiis sunt minima porro quam cum iste neque aut culpa quas reprehenderit doloribus, eveniet vero atque id?</p>\n      </t-dropdown>\n    </TInputGroup>\n\n    <TInputGroup\n      label=\"Toggle on hover\"\n      class=\"mb-4\"\n    >\n      <t-dropdown\n        toggle-on-hover\n        :toggle-on-click=\"false\"\n        :toggle-on-focus=\"false\"\n        text=\"Toggle on hover\"\n      >\n        <template #default=\"{ hide }\">\n          <div>\n            <button\n              class=\"block w-full px-4 py-2 text-sm leading-5 text-gray-700 transition duration-150 ease-in-out hover:bg-gray-100 focus:outline-none focus:bg-gray-100\"\n              role=\"menuitem\"\n            >\n              Your Profile\n            </button>\n            <button\n              class=\"block w-full px-4 py-2 text-sm leading-5 text-gray-700 transition duration-150 ease-in-out hover:bg-gray-100 focus:outline-none focus:bg-gray-100\"\n              role=\"menuitem\"\n            >\n              Settings\n            </button>\n\n            <button\n              class=\"block w-full px-4 py-2 text-sm leading-5 text-red-500 transition duration-150 ease-in-out border-t hover:bg-gray-100 focus:outline-none focus:bg-gray-100\"\n              @click=\"hide\"\n            >\n              Close me\n            </button>\n          </div>\n        </template>\n      </t-dropdown>\n    </TInputGroup>\n\n    <TInputGroup\n      label=\"Toggle on click\"\n      class=\"mb-4\"\n    >\n      <t-dropdown\n        toggle-on-click\n        :toggle-on-focus=\"false\"\n        text=\"Toggle on click\"\n      >\n        <template #default=\"{ hide }\">\n          <div>\n            <button\n              class=\"block w-full px-4 py-2 text-sm leading-5 text-gray-700 transition duration-150 ease-in-out hover:bg-gray-100 focus:outline-none focus:bg-gray-100\"\n              role=\"menuitem\"\n            >\n              Your Profile\n            </button>\n            <button\n              class=\"block w-full px-4 py-2 text-sm leading-5 text-gray-700 transition duration-150 ease-in-out hover:bg-gray-100 focus:outline-none focus:bg-gray-100\"\n              role=\"menuitem\"\n            >\n              Settings\n            </button>\n\n            <button\n              class=\"block w-full px-4 py-2 text-sm leading-5 text-red-500 transition duration-150 ease-in-out border-t hover:bg-gray-100 focus:outline-none focus:bg-gray-100\"\n              @click=\"hide\"\n            >\n              Close me\n            </button>\n          </div>\n        </template>\n      </t-dropdown>\n    </TInputGroup>\n\n    <TInputGroup\n      label=\"Toggle on click + focus\"\n      class=\"mb-4\"\n    >\n      <t-dropdown\n        text=\"Toggle on click, focus (default)\"\n      >\n        <template #default=\"{ hide }\">\n          <div>\n            <button\n              class=\"block w-full px-4 py-2 text-sm leading-5 text-gray-700 transition duration-150 ease-in-out hover:bg-gray-100 focus:outline-none focus:bg-gray-100\"\n              role=\"menuitem\"\n            >\n              Your Profile\n            </button>\n            <button\n              class=\"block w-full px-4 py-2 text-sm leading-5 text-gray-700 transition duration-150 ease-in-out hover:bg-gray-100 focus:outline-none focus:bg-gray-100\"\n              role=\"menuitem\"\n            >\n              Settings\n            </button>\n\n            <button\n              class=\"block w-full px-4 py-2 text-sm leading-5 text-red-500 transition duration-150 ease-in-out border-t hover:bg-gray-100 focus:outline-none focus:bg-gray-100\"\n              @click=\"hide\"\n            >\n              Close me\n            </button>\n          </div>\n        </template>\n      </t-dropdown>\n      <t-dropdown\n        class=\"mt-2\"\n        toggle-on-click\n        toggle-on-focus\n        toggle-on-hover\n        text=\"Toggle on click, focus + hover\"\n      >\n        <template #default=\"{ hide }\">\n          <div>\n            <button\n              class=\"block w-full px-4 py-2 text-sm leading-5 text-gray-700 transition duration-150 ease-in-out hover:bg-gray-100 focus:outline-none focus:bg-gray-100\"\n              role=\"menuitem\"\n            >\n              Your Profile\n            </button>\n            <button\n              class=\"block w-full px-4 py-2 text-sm leading-5 text-gray-700 transition duration-150 ease-in-out hover:bg-gray-100 focus:outline-none focus:bg-gray-100\"\n              role=\"menuitem\"\n            >\n              Settings\n            </button>\n\n            <button\n              class=\"block w-full px-4 py-2 text-sm leading-5 text-red-500 transition duration-150 ease-in-out border-t hover:bg-gray-100 focus:outline-none focus:bg-gray-100\"\n              @click=\"hide\"\n            >\n              Close me\n            </button>\n          </div>\n        </template>\n      </t-dropdown>\n    </TInputGroup>\n\n    <TInputGroup\n      label=\"Syncs show property\"\n      class=\"mb-4\"\n    >\n      <div>\n        <t-checkbox v-model=\"show\" />\n      </div>\n\n      <t-dropdown\n        v-model:show=\"show\"\n        class=\"mt-2\"\n        text=\"Shows as the checkbox\"\n        toggle-on-click\n        toggle-on-focus\n      >\n        <template #default=\"{ hide }\">\n          <div>\n            <button\n              class=\"block w-full px-4 py-2 text-sm leading-5 text-gray-700 transition duration-150 ease-in-out hover:bg-gray-100 focus:outline-none focus:bg-gray-100\"\n              role=\"menuitem\"\n            >\n              Your Profile\n            </button>\n            <button\n              class=\"block w-full px-4 py-2 text-sm leading-5 text-gray-700 transition duration-150 ease-in-out hover:bg-gray-100 focus:outline-none focus:bg-gray-100\"\n              role=\"menuitem\"\n            >\n              Settings\n            </button>\n\n            <button\n              class=\"block w-full px-4 py-2 text-sm leading-5 text-red-500 transition duration-150 ease-in-out border-t hover:bg-gray-100 focus:outline-none focus:bg-gray-100\"\n              @click=\"hide\"\n            >\n              Close me\n            </button>\n          </div>\n        </template>\n      </t-dropdown>\n    </TInputGroup>\n  </t-card>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nimport TCheckbox from '../components/TCheckbox.vue';\nimport TCard from '../components/TCard.vue';\nimport TDropdown from '../components/TDropdown.vue';\nimport TInputGroup from '../components/TInputGroup.vue';\n\nexport default defineComponent({\n  name: 'App',\n  components: {\n    TCheckbox,\n    TCard,\n    TDropdown,\n    TInputGroup,\n  },\n  data() {\n    return {\n      toggleOnFocus: true,\n      show: false,\n      model: '',\n    };\n  },\n\n});\n</script>\n"
  },
  {
    "path": "src/development/Home.vue",
    "content": "<template>\n  <t-card>\n    <template #header>\n      <h1>List of components</h1>\n    </template>\n\n    <t-alert>\n      Lorem ipsum dolor sit, amet consectetur adipisicing elit. Aliquam id iusto quas quaerat quasi cum alias consequuntur perspiciatis, quam ea. Quibusdam incidunt ex vel illum ab quaerat, sed tempora beatae!\n    </t-alert>\n\n    <t-input\n      v-model=\"model\"\n      placeholder=\"My placeholder\"\n      type=\"text\"\n    />\n    <t-textarea\n      v-model=\"model\"\n      placeholder=\"My placeholder\"\n    />\n    <t-select :options=\"options\" />\n    <label class=\"flex items-center\">\n      <t-checkbox checked />\n      <span class=\"ml-2\">Check me</span>\n    </label>\n\n    <div class=\"mt-2\">\n      <label class=\"flex items-center\">\n        <t-checkbox\n          v-model=\"checkboxValue\"\n          name=\"radio\"\n          value=\"hola\"\n          checked\n        />\n\n        <span class=\"ml-2\">Select this </span>\n      </label>\n      <label class=\"flex items-center\">\n        <t-checkbox\n          v-model=\"checkboxValue\"\n          name=\"radio\"\n          value=\"hello\"\n        />\n\n        <span class=\"ml-2\">And select this</span>\n      </label>\n\n      <pre>{{ checkboxValue }}</pre>\n    </div>\n\n    <div class=\"mt-2\">\n      <label class=\"flex items-center\">\n        <t-radio\n          v-model=\"radioValue\"\n          name=\"radio\"\n          value=\"1\"\n          checked\n        />\n\n        <span class=\"ml-2\">Select this ({{ radioValue }}) </span>\n      </label>\n      <label class=\"flex items-center\">\n        <t-radio\n          v-model=\"radioValue\"\n          name=\"radio\"\n          value=\"2\"\n        />\n\n        <span class=\"ml-2\">Or select this ({{ radioValue }})</span>\n      </label>\n    </div>\n\n    <div class=\"flex justify-between mt-2\">\n      <t-button>My button</t-button>\n      <t-submit>\n        TSubmit (Custom component)\n      </t-submit>\n    </div>\n\n    <template #footer>\n      <h1>Footer content</h1>\n    </template>\n  </t-card>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent, provide } from 'vue';\n\nimport TInput from '../components/TInput.vue';\nimport TSelect from '../components/TSelect.vue';\nimport TRadio from '../components/TRadio.vue';\nimport TCheckbox from '../components/TCheckbox.vue';\nimport TTextarea from '../components/TTextarea.vue';\nimport TButton from '../components/TButton.vue';\nimport TCard from '../components/TCard.vue';\nimport TAlert from '../components/TAlert.vue';\nimport TSubmit from './TSubmit.vue';\nimport { VariantJSConfiguration } from '../types';\n\nexport default defineComponent({\n  name: 'App',\n  components: {\n    TInput,\n    TTextarea,\n    TRadio,\n    TCheckbox,\n    TSelect,\n    TButton,\n    TCard,\n    TAlert,\n    TSubmit,\n  },\n  setup() {\n    provide<VariantJSConfiguration>('configuration', {\n      TSubmit: {\n        type: 'submit',\n        classes: 'block px-4 py-2 text-white transition duration-100 ease-in-out bg-red-500 border border-transparent rounded shadow-sm hover:bg-red-600 focus:border-red-500 focus:ring-2 focus:ring-red-500 focus:outline-none focus:ring-opacity-50 disabled:opacity-50 disabled:cursor-not-allowed',\n      },\n    });\n  },\n  data() {\n    return {\n      checkboxValue: [],\n      radioValue: '1',\n      model: '',\n      options: [\n        'Option A',\n        'Option B',\n        'Option C',\n      ],\n    };\n  },\n});\n</script>\n"
  },
  {
    "path": "src/development/Modal.vue",
    "content": "<template>\n  <t-card>\n    <template #header>\n      <h1>Modal</h1>\n    </template>\n\n    <TInputGroup\n      label=\"Open with modal name\"\n      class=\"mb-4\"\n    >\n      <t-modal name=\"my-modal\">\n        <template #header>\n          This it the header\n        </template>\n        <t-button\n          type=\"button\"\n          @click=\"$modal.hide('my-modal')\"\n        >\n          Hide modal\n        </t-button>\n      </t-modal>\n\n      <div class=\"flex space-x-2\">\n        <t-button\n          @click=\"$modal.show('my-modal')\"\n        >\n          Show modal\n        </t-button>\n      </div>\n    </TInputGroup>\n\n    <TInputGroup\n      label=\"Pass parameter trough the `before-show` event\"\n      class=\"mb-4\"\n    >\n      <t-modal\n        name=\"param-modal\"\n        @before-show=\"onBeforeShow\"\n        @before-hide=\"onBeforeHide\"\n      >\n        User email is: <strong>{{ user.email }}</strong>\n\n        <div class=\"mb-4\">\n          <span class=\"text-sm text-gray-600 uppercase\">set new email:</span>\n          <t-input v-model=\"email\" />\n          <span class=\"text-xs text-gray-500\">write `cancel` to prevent the modal to hide</span>\n        </div>\n      </t-modal>\n\n      <div class=\"mb-4\">\n        <span class=\"text-sm text-gray-600 uppercase\">set user email:</span>\n        <t-input v-model=\"email\" />\n        <span class=\"text-xs text-gray-500\">write `cancel` to prevent the modal to show</span>\n      </div>\n\n      <div class=\"flex space-x-2\">\n        <t-button\n          @click=\"$modal.show('param-modal', { email })\"\n        >\n          Show modal with parameter\n        </t-button>\n      </div>\n    </TInputGroup>\n\n    <TInputGroup\n\n      label=\"Open with ref\"\n      class=\"mb-4\"\n    >\n      <t-modal ref=\"modal\">\n        <template #header>\n          This it the header\n        </template>\n        <t-button\n          type=\"button\"\n          @click=\"($refs.modal as any).hide()\"\n        >\n          Hide modal\n        </t-button>\n      </t-modal>\n\n      <div class=\"flex space-x-2\">\n        <t-button\n          @click=\"($refs.modal as any).show()\"\n        >\n          Show modal\n        </t-button>\n      </div>\n    </TInputGroup>\n\n    <TInputGroup\n      label=\"Syncs show property\"\n      class=\"mb-4\"\n    >\n      <div>\n        <t-checkbox v-model=\"show\" />\n      </div>\n\n      <t-modal v-model=\"show\">\n        <template #header>\n          This it the header\n        </template>\n        <p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Repudiandae totam, alias voluptas deleniti ex tempora asperiores perspiciatis qui. Repellendus, exercitationem itaque! Beatae error ut fuga vel tempora, repellat optio molestiae!</p>\n        <template #footer>\n          this is the footer\n        </template>\n      </t-modal>\n    </TInputGroup>\n\n    <TInputGroup\n      label=\"Only closable trough the custom button inside\"\n      class=\"mb-4\"\n    >\n      <t-button @click=\"$modal.show('notClosable')\">\n        Show modal\n      </t-button>\n\n      <t-modal\n        name=\"notClosable\"\n        :esc-to-close=\"false\"\n        :click-to-close=\"false\"\n        hide-close-button\n      >\n        <template #default=\"{ hide }\">\n          <t-button @click=\"() => hide()\">\n            Close this\n          </t-button>\n        </template>\n      </t-modal>\n    </TInputGroup>\n  </t-card>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nimport { Data } from '@variantjs/core';\nimport TCheckbox from '../components/TCheckbox.vue';\nimport TButton from '../components/TButton.vue';\nimport TCard from '../components/TCard.vue';\nimport TModal from '../components/TModal.vue';\nimport TInput from '../components/TInput.vue';\nimport TInputGroup from '../components/TInputGroup.vue';\n\nexport default defineComponent({\n  name: 'App',\n  components: {\n    TButton,\n    TCheckbox,\n    TCard,\n    TModal,\n    TInput,\n    TInputGroup,\n  },\n  data() {\n    return {\n      show: false,\n      email: 'alfonso@variantjs.com',\n      name: 'Alfonso',\n      user: {} as Data,\n    };\n  },\n  methods: {\n    onBeforeShow({ params, cancel }: { params: { email: string }, cancel: () => void }) {\n      const { email } = params;\n      if (email === 'cancel') {\n        cancel();\n        return;\n      }\n\n      this.user = {\n        email,\n      };\n    },\n    onBeforeHide({ cancel }: { cancel: () => void }) {\n      if (this.email === 'cancel') {\n        cancel();\n      }\n    },\n  },\n});\n</script>\n"
  },
  {
    "path": "src/development/Multioptions.vue",
    "content": "<template>\n  <t-card\n    header=\"Multioptions\"\n  >\n    <div class=\"grid grid-cols-1 gap-6\">\n      <p>Multioptions components v-model sync</p>\n      <t-select\n        v-model=\"selected\"\n        multiple\n        :options=\"options\"\n      />\n\n      <t-rich-select\n        v-model=\"selected\"\n        placeholder=\"select an option\"\n        :options=\"options\"\n        multiple\n      />\n\n      <t-rich-select\n        v-model=\"selected\"\n        placeholder=\"select an option\"\n        :options=\"options\"\n        multiple\n        tags\n      />\n    </div>\n  </t-card>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\nimport TSelect from '../components/TSelect.vue';\nimport TCard from '../components/TCard.vue';\nimport TRichSelect from '../components/TRichSelect.vue';\n\nexport default defineComponent({\n  name: 'Multioptions',\n  components: {\n    TSelect,\n    TRichSelect,\n    TCard,\n  },\n  data() {\n    return {\n      selected2: null,\n      selected: ['b', 'c', 'd'],\n      options: [\n        {\n          value: 'a',\n          text: 'Option A',\n        },\n        {\n          value: 'b',\n          text: 'Option B',\n        },\n        {\n          value: 'c',\n          text: 'Option C',\n        },\n        {\n          value: 'd',\n          text: 'Option D',\n          disabled: true,\n        },\n        {\n          value: 'e',\n          text: 'Option E',\n        },\n        {\n          value: 'f',\n          text: 'Option F',\n          disabled: true,\n        },\n      ],\n    };\n  },\n});\n</script>\n"
  },
  {
    "path": "src/development/Options.vue",
    "content": "<template>\n  <t-card header=\"Options\">\n    <div class=\"grid grid-cols-1 gap-6\">\n      <p>Options components v-model sync</p>\n      <t-select\n        v-model=\"selected\"\n        :options=\"options\"\n      />\n\n      <t-rich-select\n        v-model=\"selected\"\n        placeholder=\"select an option\"\n        :options=\"options\"\n      />\n\n      <t-rich-select\n        v-model=\"selected\"\n        placeholder=\"select an option\"\n        :options=\"options\"\n      />\n\n      <t-rich-select\n        placeholder=\"select an option\"\n        :fetch-options=\"fetchOptions\"\n        :minimum-input-length=\"3\"\n        value-attribute=\"imdbID\"\n        text-attribute=\"Title\"\n      >\n        <template #option=\"{ option: { raw: movie }, className, isSelected }\">\n          <div\n            class=\"flex flex-col items-center px-3 py-2 space-x-4 overflow-auto bg-white sm:flex-row\"\n            :class=\"className\"\n          >\n            <div\n              class=\"flex-shrink-0 w-10 h-10 bg-gray-500 bg-center bg-cover rounded\"\n              :style=\"{ backgroundImage: `url(${movie?.Poster})` }\"\n            />\n            <div class=\"flex flex-col w-full overflow-auto\">\n              <div class=\"flex-grow overflow-auto\">\n                <h3\n                  class=\"font-semibold truncate \"\n                  :class=\"{\n                    'text-white': isSelected,\n                    'text-gray-800': !isSelected,\n                  }\"\n                >\n                  {{ movie?.Title }}\n                </h3>\n                <p\n                  class=\"text-sm \"\n                  :class=\"{\n                    'text-white': isSelected,\n                    'text-gray-400': !isSelected,\n                  }\"\n                >\n                  {{ movie?.Year }}\n                </p>\n              </div>\n            </div>\n          </div>\n        </template>\n      </t-rich-select>\n\n      <t-rich-select\n        placeholder=\"select an option\"\n        :options=\"[1,2,3,4]\"\n        hide-search-box\n      />\n    </div>\n\n    <t-button @click=\"selected = null\">\n      Clear value\n    </t-button>\n  </t-card>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\nimport TSelect from '../components/TSelect.vue';\nimport TRichSelect from '../components/TRichSelect.vue';\nimport TButton from '../components/TButton.vue';\nimport TCard from '../components/TCard.vue';\n\nconst fetchOptions = (query?: string, nextPage?: number) => {\n  const url = `https://www.omdbapi.com/?apikey=e1b3617e&s=${query}&page=${nextPage || 1}`;\n\n  return fetch(url)\n    .then((response) => response.json())\n    .then((data) => ({\n      results: data.Search as Record<string, any>[],\n      hasMorePages: data.Search && data.totalResults > (data.Search.length * (nextPage || 1)) * 10,\n    }));\n};\n\nexport default defineComponent({\n  name: 'Options',\n  components: {\n    TSelect,\n    TCard,\n    TButton,\n    TRichSelect,\n  },\n  data() {\n    return {\n      fetchOptions,\n      selected: 'A' as string | null,\n      newOption: '',\n      selectedUser: null,\n      users: [\n        {\n          email: 'alfonso@vexilo.com',\n          name: 'Alfonso Bribiesca',\n        },\n        {\n          email: 'saida@gmail.com',\n          name: 'Saida Redondo',\n        },\n      ],\n      options: [\n        { value: 'A', text: 'Option A' },\n        {\n          value: 'B',\n          text: 'Option B',\n          children: [\n\n            { value: 1, text: 'Option B1' },\n            { value: 2, text: 'Option B2', children: ['Blue', 'Red', 'Yellow'] },\n            { value: 3, text: 'Option B3' },\n          ],\n        },\n        { value: 'C', text: 'Option C' },\n      ],\n      // options: ['Blue', 'Red', 'Yellow', 'Green'],\n    };\n  },\n});\n</script>\n"
  },
  {
    "path": "src/development/RichSelect.vue",
    "content": "<template>\n  <t-card header=\"RichSelect\">\n    <t-input-group\n      label=\"Disabled rich select\"\n      class=\"mb-4\"\n    >\n      <t-rich-select\n        v-model=\"selected\"\n        :options=\"options\"\n        placeholder=\"Disabled\"\n        disabled\n      />\n    </t-input-group>\n\n    <t-input-group\n      label=\"Preselect option with an inital set\"\n      class=\"mb-4\"\n    >\n      <t-rich-select\n        v-model=\"preselectedOption\"\n        :options=\"initialSet\"\n        :fetch-options=\"fetchOptions\"\n        :minimum-input-length=\"3\"\n        value-attribute=\"imdbID\"\n        text-attribute=\"Title\"\n      />\n    </t-input-group>\n\n    <t-input-group\n      label=\"Select the option if the options change dinamically\"\n      class=\"mb-4\"\n    >\n      <t-rich-select\n        v-model=\"preselectedOption2\"\n        :options=\"dynamicSet\"\n        :fetch-options=\"fetchOptions\"\n        :minimum-input-length=\"3\"\n        value-attribute=\"imdbID\"\n        text-attribute=\"Title\"\n      />\n    </t-input-group>\n\n    <t-input-group\n      label=\"Prefetch options\"\n      class=\"mb-4\"\n    >\n      <t-rich-select\n        v-model=\"preselectedOption3\"\n        :fetch-options=\"fetchOptions\"\n        :minimum-input-length=\"3\"\n        value-attribute=\"imdbID\"\n        text-attribute=\"Title\"\n        :prefetch-options=\"prefetchOptions\"\n      />\n    </t-input-group>\n\n    <t-input-group\n      label=\"Clear search on close\"\n      class=\"mb-4\"\n    >\n      <t-rich-select\n        v-model=\"selected\"\n        :options=\"options\"\n        :hide-search-box=\"false\"\n        :clear-search-on-close=\"true\"\n      />\n    </t-input-group>\n\n    <t-input-group\n      label=\"With teleport\"\n      class=\"mb-4\"\n    >\n      <t-rich-select\n        v-model=\"selected\"\n        :options=\"options\"\n        :teleport=\"true\"\n      />\n    </t-input-group>\n  </t-card>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\nimport TRichSelect from '../components/TRichSelect.vue';\nimport TInputGroup from '../components/TInputGroup.vue';\nimport TCard from '../components/TCard.vue';\nimport { PreFetchOptionsFn } from '../types';\n\nconst fetchOptions = (query?: string, nextPage?: number) => {\n  const url = `https://www.omdbapi.com/?apikey=e1b3617e&s=${query}&page=${nextPage || 1}`;\n\n  return fetch(url)\n    .then((response) => response.json())\n    .then((data) => ({\n      results: data.Search as Record<string, any>[],\n      hasMorePages: data.Search && data.totalResults > (data.Search.length * (nextPage || 1)) * 10,\n    }));\n};\n\nconst prefetchOptions: PreFetchOptionsFn = (currentValue: any) => {\n  const url = `https://www.omdbapi.com/?apikey=e1b3617e&i=${currentValue}`;\n\n  return fetch(url)\n    .then((response) => response.json())\n    .then((data) => [data]);\n};\n\nexport default defineComponent({\n  name: 'RichSelect',\n  components: {\n    TCard,\n    TRichSelect,\n    TInputGroup,\n  },\n  data() {\n    return {\n      fetchOptions,\n      prefetchOptions,\n      initialSet: [\n        {\n          Title: 'The Matrix',\n          Year: '1999',\n          imdbID: 'tt0133093',\n          Type: 'movie',\n          Poster: 'https://m.media-amazon.com/images/M/MV5BNzQzOTk3OTAtNDQ0Zi00ZTVkLWI0MTEtMDllZjNkYzNjNTc4L2ltYWdlXkEyXkFqcGdeQXVyNjU0OTQ0OTY@._V1_SX300.jpg',\n        },\n      ],\n      dynamicSet: [] as Record<string, unknown>[],\n      preselectedOption: 'tt0133093',\n      preselectedOption2: 'tt0133093',\n      preselectedOption3: 'tt0133093',\n      selected: 'A' as string | null,\n      newOption: '',\n      selectedUser: null,\n      users: [\n        {\n          email: 'alfonso@vexilo.com',\n          name: 'Alfonso Bribiesca',\n        },\n        {\n          email: 'saida@gmail.com',\n          name: 'Saida Redondo',\n        },\n      ],\n      options: [\n        { value: 'A', text: 'Option A' },\n        {\n          value: 'B',\n          text: 'Option B',\n          children: [\n\n            { value: 1, text: 'Option B1' },\n            { value: 2, text: 'Option B2', children: ['Blue', 'Red', 'Yellow'] },\n            { value: 3, text: 'Option B3' },\n          ],\n        },\n        { value: 'C', text: 'Option C' },\n      ],\n      // options: ['Blue', 'Red', 'Yellow', 'Green'],\n    };\n  },\n\n  mounted() {\n    setTimeout(() => {\n      this.dynamicSet = [\n        {\n          Title: 'The Matrix',\n          Year: '1999',\n          imdbID: 'tt0133093',\n          Type: 'movie',\n          Poster: 'https://m.media-amazon.com/images/M/MV5BNzQzOTk3OTAtNDQ0Zi00ZTVkLWI0MTEtMDllZjNkYzNjNTc4L2ltYWdlXkEyXkFqcGdeQXVyNjU0OTQ0OTY@._V1_SX300.jpg',\n        },\n      ];\n    }, 2000);\n  },\n});\n</script>\n"
  },
  {
    "path": "src/development/TSubmit.vue",
    "content": "<script lang=\"ts\">\nimport { defineComponent } from 'vue';\nimport TButton from '../components/TButton.vue';\n\nexport default defineComponent({\n  name: 'TSubmit',\n  extends: TButton,\n  setup: TButton.setup,\n});\n</script>\n"
  },
  {
    "path": "src/development/Theme.vue",
    "content": "<template>\n  <t-card class=\"w-full\">\n    <template #header>\n      Simple component\n    </template>\n\n    <div class=\"grid grid-cols-1 gap-6\">\n      <p>Disable all classes</p>\n\n      <div class=\"p-2 bg-gray-100 transparency\">\n        <t-button\n          :fixed-classes=\"undefined\"\n          :classes=\"undefined\"\n          :class=\"undefined\"\n        >\n          Press me!\n        </t-button>\n      </div>\n\n      <p>Override something with the native `class`</p>\n      <t-button class=\"text-red-600\">\n        Press me!\n      </t-button>\n\n      <p>Get the variant from...</p>\n\n      <div class=\"flex space-x-3\">\n        <label class=\"flex items-center\">\n          <t-radio\n            v-model=\"variant\"\n            :value=\"null\"\n            name=\"variant\"\n          />\n\n          <span class=\"ml-2\">Default</span>\n        </label>\n        <label class=\"flex items-center\">\n          <t-radio\n            v-model=\"variant\"\n            value=\"error\"\n            name=\"variant\"\n          />\n\n          <span class=\"ml-2\">Error</span>\n        </label>\n        <label class=\"flex items-center\">\n          <t-radio\n            v-model=\"variant\"\n            value=\"success\"\n            name=\"variant\"\n          />\n\n          <span class=\"ml-2\">Success</span>\n        </label>\n      </div>\n\n      <t-button\n        :variant=\"variant\"\n        :variants=\"variants\"\n      >\n        ...the variant  prop\n      </t-button>\n\n      <t-button\n        :classes=\"[{\n          'block px-4 py-2 text-white transition duration-100 ease-in-out bg-red-500 border border-transparent rounded shadow-sm hover:bg-red-600 focus:border-red-500 focus:ring-2 focus:ring-red-500 focus:outline-none focus:ring-opacity-50 disabled:opacity-50 disabled:cursor-not-allowed': variant === 'error'\n        }, variant !== 'error' ? defaultTheme : '']\"\n      >\n        ...a condition\n      </t-button>\n\n      <t-button\n        :variant=\"variant\"\n      >\n        ...the configuration\n      </t-button>\n    </div>\n  </t-card>\n\n  <t-card class=\"w-full\">\n    <template #header>\n      Complex for component\n    </template>\n\n    <div class=\"grid grid-cols-1 gap-6\">\n      <p>Disable all classes</p>\n\n      <div class=\"p-2 bg-gray-100 transparency\">\n        <t-card\n          :fixed-classes=\"{\n            wrapper: '',\n            body: '',\n            header: '',\n            footer: '',\n          }\"\n          :classes=\"{\n            wrapper: '',\n            body: '',\n            header: '',\n            footer: '',\n          }\"\n        >\n          Im a card without styles\n        </t-card>\n      </div>\n\n      <p>Override the wrapper class with the native `class`</p>\n      <t-card class=\"border-red-600\">\n        I should have a red border\n      </t-card>\n\n      <p>Get the variant from...</p>\n\n      <div class=\"flex space-x-3\">\n        <label class=\"flex items-center\">\n          <t-radio\n            v-model=\"variant\"\n            :value=\"null\"\n            name=\"variant-card\"\n          />\n\n          <span class=\"ml-2\">Default</span>\n        </label>\n        <label class=\"flex items-center\">\n          <t-radio\n            v-model=\"variant\"\n            value=\"error\"\n            name=\"variant-card\"\n          />\n\n          <span class=\"ml-2\">Error</span>\n        </label>\n        <label class=\"flex items-center\">\n          <t-radio\n            v-model=\"variant\"\n            value=\"success\"\n            name=\"variant-card\"\n          />\n\n          <span class=\"ml-2\">Success</span>\n        </label>\n      </div>\n\n      <t-card\n        :variant=\"variant\"\n        :variants=\"cardVariants\"\n      >\n        ...the variant  prop\n      </t-card>\n\n      <t-card\n        :classes=\"{\n          body: {\n            'p-3 text-red-600 bg-red-100': variant === 'error',\n            'p-3 text-green-600 bg-green-100': variant === 'success',\n          },\n        }\"\n      >\n        ...a condition\n      </t-card>\n\n      <t-card\n        :variant=\"variant\"\n      >\n        ...the configuration\n      </t-card>\n\n      <t-card>\n        ...the configuration\n      </t-card>\n    </div>\n  </t-card>\n</template>\n\n<script lang=\"ts\">\nimport { TButtonConfig, TCardConfig } from '@variantjs/core';\nimport { defineComponent, provide } from 'vue';\nimport TButton from '../components/TButton.vue';\nimport TRadio from '../components/TRadio.vue';\nimport TCard from '../components/TCard.vue';\n\nconst variants = {\n  error: {\n    classes: 'block px-4 py-2 text-white transition duration-100 ease-in-out bg-red-500 border border-transparent rounded shadow-sm hover:bg-red-600 focus:border-red-500 focus:ring-2 focus:ring-red-500 focus:outline-none focus:ring-opacity-50 disabled:opacity-50 disabled:cursor-not-allowed',\n  },\n  success: {\n    classes: 'block px-4 py-2 text-white transition duration-100 ease-in-out bg-green-500 border border-transparent rounded shadow-sm hover:bg-green-600 focus:border-green-500 focus:ring-2 focus:ring-red-500 focus:outline-none focus:ring-opacity-50 disabled:opacity-50 disabled:cursor-not-allowed',\n  },\n};\n\nconst cardVariants = {\n  error: {\n    fixedClasses: {\n      body: 'text-white',\n    },\n    classes: {\n      body: 'p-3 bg-red-600',\n    },\n  },\n  success: {\n    classes: {\n      body: 'p-3 text-green-600 bg-green-100',\n    },\n  },\n};\n\nexport default defineComponent({\n  name: 'Theme',\n  components: {\n    TButton,\n    TRadio,\n    TCard,\n  },\n  setup() {\n    provide('configuration', {\n      TButton: {\n        variants,\n      },\n      TCard: {\n        variants: cardVariants,\n      },\n    });\n  },\n  data() {\n    return {\n      variants,\n      variant: 'error',\n      defaultTheme: TButtonConfig.classes,\n      cardVariants,\n      defaultCardConfig: TCardConfig.classes,\n    };\n  },\n});\n</script>\n\n<style>\n.transparency {\nbackground-color: #ffffff;\nbackground-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3E%3Cg fill='%23707070' fill-opacity='0.25'%3E%3Cpath fill-rule='evenodd' d='M0 0h4v4H0V0zm4 4h4v4H4V4z'/%3E%3C/g%3E%3C/svg%3E\");\n}\n</style>\n"
  },
  {
    "path": "src/development/router.ts",
    "content": "import { createRouter, createWebHashHistory } from 'vue-router';\n\nimport Home from './Home.vue';\nimport About from './About.vue';\nimport Options from './Options.vue';\nimport Multioptions from './Multioptions.vue';\nimport Dropdown from './Dropdown.vue';\nimport Alert from './Alert.vue';\nimport Modal from './Modal.vue';\nimport Dialog from './Dialog.vue';\nimport Checkbox from './Check.vue';\nimport Theme from './Theme.vue';\nimport RichSelect from './RichSelect.vue';\nimport Attributes from './Attributes.vue';\n\nconst routes = [\n  { path: '/', component: Home },\n  { path: '/about', component: About },\n  { path: '/options', component: Options },\n  { path: '/multioptions', component: Multioptions },\n  { path: '/dropdown', component: Dropdown },\n  { path: '/alert', component: Alert },\n  { path: '/modal', component: Modal },\n  { path: '/dialog', component: Dialog },\n  { path: '/theme', component: Theme },\n  { path: '/attributes', component: Attributes },\n  { path: '/checkbox', component: Checkbox },\n  { path: '/rich-select', component: RichSelect },\n];\n\nconst router = createRouter({\n  history: createWebHashHistory(),\n  routes,\n});\n\nexport default router;\n"
  },
  {
    "path": "src/icons/CheckCircleIcon.vue",
    "content": "<template>\n  <svg\n    xmlns=\"http://www.w3.org/2000/svg\"\n    fill=\"none\"\n    viewBox=\"0 0 24 24\"\n    stroke=\"currentColor\"\n  >\n    <path\n      stroke-linecap=\"round\"\n      stroke-linejoin=\"round\"\n      stroke-width=\"2\"\n      d=\"M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z\"\n    />\n  </svg>\n</template>\n"
  },
  {
    "path": "src/icons/CheckmarkIcon.vue",
    "content": "<template>\n  <svg\n    xmlns=\"http://www.w3.org/2000/svg\"\n    viewBox=\"0 0 20 20\"\n    fill=\"currentColor\"\n  >\n    <path\n      fill-rule=\"evenodd\"\n      d=\"M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z\"\n      clip-rule=\"evenodd\"\n    />\n  </svg>\n</template>\n"
  },
  {
    "path": "src/icons/CloseIcon.vue",
    "content": "<template>\n  <svg\n    xmlns=\"http://www.w3.org/2000/svg\"\n    fill=\"none\"\n    viewBox=\"0 0 24 24\"\n    stroke=\"currentColor\"\n  ><path\n    stroke-linecap=\"round\"\n    stroke-linejoin=\"round\"\n    stroke-width=\"2\"\n    d=\"M6 18L18 6M6 6l12 12\"\n  /></svg>\n</template>\n"
  },
  {
    "path": "src/icons/CrossCircleIcon.vue",
    "content": "<template>\n  <svg\n    xmlns=\"http://www.w3.org/2000/svg\"\n    fill=\"none\"\n    viewBox=\"0 0 24 24\"\n    stroke=\"currentColor\"\n  >\n    <path\n      stroke-linecap=\"round\"\n      stroke-linejoin=\"round\"\n      stroke-width=\"2\"\n      d=\"M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z\"\n    />\n  </svg>\n</template>\n"
  },
  {
    "path": "src/icons/CustomIcon.vue",
    "content": "<template>\n  <component :is=\"child\" />\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent, PropType } from 'vue';\nimport { IconProp } from '../types';\nimport { svgToVueComponent } from '../utils/svgToVueComponent';\n\n// @vue/component\nexport default defineComponent({\n  name: 'CustomIcon',\n  compatConfig: {\n    MODE: 3,\n  },\n  props: {\n    icon: {\n      type: [Object, String] as PropType<IconProp>,\n      required: true,\n    },\n  },\n  data() {\n    return {\n      child: this.icon instanceof Element || typeof this.icon === 'string' ? svgToVueComponent(this.icon) : this.icon,\n    };\n  },\n});\n</script>\n"
  },
  {
    "path": "src/icons/ExclamationIcon.vue",
    "content": "<template>\n  <svg\n    xmlns=\"http://www.w3.org/2000/svg\"\n    fill=\"none\"\n    viewBox=\"0 0 24 24\"\n    stroke=\"currentColor\"\n  >\n    <path\n      stroke-linecap=\"round\"\n      stroke-linejoin=\"round\"\n      stroke-width=\"2\"\n      d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\n    />\n  </svg>\n</template>\n"
  },
  {
    "path": "src/icons/InformationCircleIcon.vue",
    "content": "<template>\n  <svg\n    xmlns=\"http://www.w3.org/2000/svg\"\n    class=\"w-6 h-6\"\n    fill=\"none\"\n    viewBox=\"0 0 24 24\"\n    stroke=\"currentColor\"\n  >\n    <path\n      stroke-linecap=\"round\"\n      stroke-linejoin=\"round\"\n      stroke-width=\"2\"\n      d=\"M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\"\n    />\n  </svg>\n</template>\n"
  },
  {
    "path": "src/icons/LoadingIcon.vue",
    "content": "<template>\n  <svg\n    viewBox=\"0 0 20 20\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n  >\n    <circle\n      cx=\"10\"\n      cy=\"10\"\n      fill=\"none\"\n      r=\"8\"\n      stroke-width=\"2\"\n      stroke=\"currentColor\"\n      transform-origin=\"center\"\n      opacity=\"0.2\"\n    />\n    <circle\n      cx=\"10\"\n      cy=\"10\"\n      fill=\"none\"\n      r=\"8\"\n      stroke-width=\"2\"\n      stroke=\"currentColor\"\n      stroke-dasharray=\"80\"\n      stroke-dashoffset=\"60\"\n      transform-origin=\"center\"\n    >\n      <animateTransform\n        attributeType=\"xml\"\n        attributeName=\"transform\"\n        type=\"rotate\"\n        from=\"0\"\n        to=\"360\"\n        begin=\"0\"\n        dur=\"1s\"\n        repeatCount=\"indefinite\"\n      />\n    </circle>\n  </svg>\n</template>\n"
  },
  {
    "path": "src/icons/QuestionMarkCircleIcon.vue",
    "content": "<template>\n  <svg\n    xmlns=\"http://www.w3.org/2000/svg\"\n    fill=\"none\"\n    viewBox=\"0 0 24 24\"\n    stroke=\"currentColor\"\n  >\n    <path\n      stroke-linecap=\"round\"\n      stroke-linejoin=\"round\"\n      stroke-width=\"2\"\n      d=\"M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z\"\n    />\n  </svg>\n</template>\n"
  },
  {
    "path": "src/icons/SelectorIcon.vue",
    "content": "<template>\n  <svg\n    fill=\"currentColor\"\n    xmlns=\"http://www.w3.org/2000/svg\"\n    viewBox=\"0 0 20 20\"\n  ><path\n    clip-rule=\"evenodd\"\n    fill-rule=\"evenodd\"\n    d=\"M10 3a1 1 0 01.707.293l3 3a1 1 0 01-1.414 1.414L10 5.414 7.707 7.707a1 1 0 01-1.414-1.414l3-3A1 1 0 0110 3zm-3.707 9.293a1 1 0 011.414 0L10 14.586l2.293-2.293a1 1 0 011.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z\"\n  /></svg>\n</template>\n"
  },
  {
    "path": "src/icons/SolidCheckCircleIcon.vue",
    "content": "<template>\n  <svg\n    xmlns=\"http://www.w3.org/2000/svg\"\n    viewBox=\"0 0 20 20\"\n    fill=\"currentColor\"\n  >\n    <path\n      fill-rule=\"evenodd\"\n      d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z\"\n      clip-rule=\"evenodd\"\n    />\n  </svg>\n</template>\n"
  },
  {
    "path": "src/icons/SolidCrossCircleIcon.vue",
    "content": "<template>\n  <svg\n    xmlns=\"http://www.w3.org/2000/svg\"\n    viewBox=\"0 0 20 20\"\n    fill=\"currentColor\"\n  >\n    <path\n      fill-rule=\"evenodd\"\n      d=\"M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z\"\n      clip-rule=\"evenodd\"\n    />\n  </svg>\n</template>\n"
  },
  {
    "path": "src/icons/SolidExclamationIcon.vue",
    "content": "<template>\n  <svg\n    xmlns=\"http://www.w3.org/2000/svg\"\n    viewBox=\"0 0 20 20\"\n    fill=\"currentColor\"\n  >\n    <path\n      fill-rule=\"evenodd\"\n      d=\"M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z\"\n      clip-rule=\"evenodd\"\n    />\n  </svg>\n</template>\n"
  },
  {
    "path": "src/icons/SolidInformationCircleIcon.vue",
    "content": "<template>\n  <svg\n    xmlns=\"http://www.w3.org/2000/svg\"\n    viewBox=\"0 0 20 20\"\n    fill=\"currentColor\"\n  >\n    <path\n      fill-rule=\"evenodd\"\n      d=\"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z\"\n      clip-rule=\"evenodd\"\n    />\n  </svg>\n</template>\n"
  },
  {
    "path": "src/icons/SolidQuestionMarkCircleIcon.vue",
    "content": "<template>\n  <svg\n    xmlns=\"http://www.w3.org/2000/svg\"\n    viewBox=\"0 0 20 20\"\n    fill=\"currentColor\"\n  >\n    <path\n      fill-rule=\"evenodd\"\n      d=\"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-8-3a1 1 0 00-.867.5 1 1 0 11-1.731-1A3 3 0 0113 8a3.001 3.001 0 01-2 2.83V11a1 1 0 11-2 0v-1a1 1 0 011-1 1 1 0 100-2zm0 8a1 1 0 100-2 1 1 0 000 2z\"\n      clip-rule=\"evenodd\"\n    />\n  </svg>\n</template>\n"
  },
  {
    "path": "src/index.ts",
    "content": "// Import Utils\nimport { Emitter } from './utils/emitter';\nimport { getVariantProps, getVariantPropsWithClassesList } from './utils/getVariantProps';\nimport { sameWidthModifier } from './utils/popper';\nimport { svgToVueComponent } from './utils/svgToVueComponent';\n\nimport plugin from './plugin';\n\n// Import Components\nimport TInput from './components/TInput.vue';\nimport TButton from './components/TButton.vue';\nimport TTextarea from './components/TTextarea.vue';\nimport TSelect from './components/TSelect.vue';\nimport TCheckbox from './components/TCheckbox.vue';\nimport TRadio from './components/TRadio.vue';\nimport TAlert from './components/TAlert.vue';\nimport TCard from './components/TCard.vue';\nimport TDropdown from './components/TDropdown.vue';\nimport TInputGroup from './components/TInputGroup.vue';\nimport TRichSelect from './components/TRichSelect.vue';\nimport TTag from './components/TTag.vue';\nimport TToggle from './components/TToggle.vue';\nimport TModal from './components/TModal.vue';\nimport TDialog from './components/TDialog.vue';\n\n// Import icons\nimport LoadingIcon from './icons/LoadingIcon.vue';\n\n// Import uses\nimport useActivableOption from './use/useActivableOption';\nimport useConfiguration from './use/useConfiguration';\nimport useConfigurationWithClassesList from './use/useConfigurationWithClassesList';\nimport useFetchsOptions from './use/useFetchsOptions';\nimport useInjectsClassesList from './use/useInjectsClassesList';\nimport useInjectsClassesListClass from './use/useInjectsClassesListClass';\nimport useInjectsConfiguration from './use/useInjectsConfiguration';\nimport useMulipleableVModel from './use/useMulipleableVModel';\nimport useMultioptions from './use/useMultioptions';\nimport useSelectableOption from './use/useSelectableOption';\nimport useVModel from './use/useVModel';\n\nexport * from './types';\n\n// Export components\nexport {\n  // Basic Form Components\n  TInput,\n  TButton,\n  TTextarea,\n  TSelect,\n  TCheckbox,\n  TRadio,\n\n  // Form Components\n  TInputGroup,\n  TRichSelect,\n\n  // Single tag components\n  TTag,\n\n  // Components\n  TCard,\n  TDropdown,\n  TAlert,\n  TModal,\n  TDialog,\n  TToggle,\n\n  // Installer\n  plugin as variantJS,\n};\n\n// Export icons\nexport {\n  LoadingIcon,\n};\n\n// Export utils\nexport {\n  Emitter,\n  getVariantProps,\n  getVariantPropsWithClassesList,\n  sameWidthModifier,\n  svgToVueComponent,\n};\n\n// Export uses\nexport {\n  useActivableOption,\n  useConfiguration,\n  useConfigurationWithClassesList,\n  useFetchsOptions,\n  useInjectsClassesList,\n  useInjectsClassesListClass,\n  useInjectsConfiguration,\n  useMulipleableVModel,\n  useMultioptions,\n  useSelectableOption,\n  useVModel,\n};\n"
  },
  {
    "path": "src/main.ts",
    "content": "import './assets/tailwind.css';\nimport { createApp } from 'vue';\nimport plugin from './plugin';\nimport { VariantJSConfiguration } from './types/variantCore';\n\nimport App from './development/App.vue';\n\nimport router from './development/router';\n\nconst app = createApp(App);\n\napp.use(router);\n\nconst configuration: VariantJSConfiguration = {\n  TCard: {\n    classes: {\n      wrapper: 'bg-white border border-gray-100 rounded shadow-sm w-full',\n    },\n  },\n};\n\napp.use(plugin, configuration);\n\napp.mount('#app');\n"
  },
  {
    "path": "src/plugin.ts",
    "content": "import {\n  DialogHideFn, DialogProgramaticallyShowFn, DialogResponse, DialogShowFn, DialogType, ModalHideFn, ModalShowFn,\n} from '@variantjs/core';\nimport { App } from 'vue';\nimport { VariantJSConfiguration } from './types';\nimport { TDialogOptions } from './types/components/t-dialog';\nimport createDialogProgramatically from './utils/createDialogProgramatically';\nimport { Emitter } from './utils/emitter';\n\nconst plugin = {\n  install: (app: App<Element>, configuration: VariantJSConfiguration = {}): void => {\n    const emitter = new Emitter();\n\n    // @TODO: ensure this variable is exposed for https://vuetelescope.com/\n    // eslint-disable-next-line no-param-reassign\n    app.config.globalProperties.$variantJS = true;\n\n    // eslint-disable-next-line no-param-reassign\n    app.config.globalProperties.$modal = {\n      show(name: string, params?: { [k: string]: string }) {\n        emitter.emit('modal:show', name, params);\n      },\n      hide(name: string) {\n        emitter.emit('modal:hide', name);\n      },\n    };\n\n    const alert: DialogProgramaticallyShowFn = (titleOrDialogOptions: TDialogOptions | string, text?: string, icon?: string) : Promise<DialogResponse> => createDialogProgramatically(configuration, DialogType.Alert, titleOrDialogOptions, text, icon);\n\n    const prompt: DialogProgramaticallyShowFn = (titleOrDialogOptions: TDialogOptions | string, text?: string, icon?: string) : Promise<DialogResponse> => createDialogProgramatically(configuration, DialogType.Prompt, titleOrDialogOptions, text, icon);\n\n    const confirm: DialogProgramaticallyShowFn = (titleOrDialogOptions: TDialogOptions | string, text?: string, icon?: string) : Promise<DialogResponse> => createDialogProgramatically(configuration, DialogType.Confirm, titleOrDialogOptions, text, icon);\n\n    // eslint-disable-next-line no-param-reassign\n    app.config.globalProperties.$dialog = {\n      show(name: string): Promise<DialogResponse> {\n        const promise = new Promise((resolve, reject) => {\n          emitter.emit('dialog:show', name, resolve, reject);\n        });\n\n        return promise as Promise<DialogResponse>;\n      },\n      hide(name: string) {\n        emitter.emit('dialog:hide', name);\n      },\n      alert,\n      confirm,\n      prompt,\n    };\n\n    // eslint-disable-next-line no-param-reassign\n    app.config.globalProperties.$alert = alert;\n    // eslint-disable-next-line no-param-reassign\n    app.config.globalProperties.$confirm = confirm;\n    // eslint-disable-next-line no-param-reassign\n    app.config.globalProperties.$prompt = prompt;\n\n    app.provide('configuration', configuration);\n\n    app.provide('emitter', emitter);\n  },\n};\n\ndeclare module '@vue/runtime-core' {\n  interface ComponentCustomProperties {\n    $variantJS: boolean;\n    $modal: {\n      show: ModalShowFn;\n      hide: ModalHideFn;\n    },\n    $dialog: {\n      show: DialogShowFn;\n      hide: DialogHideFn;\n      alert: DialogProgramaticallyShowFn;\n      confirm: DialogProgramaticallyShowFn;\n      prompt: DialogProgramaticallyShowFn;\n    },\n    $alert: DialogProgramaticallyShowFn;\n    $confirm: DialogProgramaticallyShowFn;\n    $prompt: DialogProgramaticallyShowFn;\n  }\n}\n\nexport default plugin;\n"
  },
  {
    "path": "src/shims-vue.d.ts",
    "content": "/* eslint-disable @typescript-eslint/ban-types */\ndeclare module '*.vue' {\n  import { DefineComponent } from 'vue';\n\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  const component: DefineComponent<{}, {}, any>;\n  export default component;\n}\n"
  },
  {
    "path": "src/types/components/t-alert.ts",
    "content": "import { WithVariantPropsAndClassesList, TAlertClassesValidKeys, Data } from '@variantjs/core';\nimport { HTMLAttributes } from 'vue';\nimport { IconProp } from '../misc';\n\nexport type TAlertOptions = WithVariantPropsAndClassesList<{\n  text?: string,\n  tagName?: string,\n  bodyTagName?: string,\n  dismissible?: boolean,\n  show?: boolean,\n  timeout?: number,\n  animate?: boolean,\n  closeIcon?: IconProp,\n} & HTMLAttributes & Data, TAlertClassesValidKeys>;\n"
  },
  {
    "path": "src/types/components/t-button.ts",
    "content": "import { Data, WithVariantProps } from '@variantjs/core';\nimport { ButtonHTMLAttributes } from 'vue';\nimport { VueRouteAriaCurrentValue, VueRouteRouteLocationRaw } from '../vueRouter';\n\ntype RouterLinkProps = {\n  to?: VueRouteRouteLocationRaw,\n  replace?: boolean,\n  activeClass?: string,\n  exactActiveClass?: string,\n  custom?: boolean,\n  ariaCurrentValue?: VueRouteAriaCurrentValue,\n};\n\nexport type TButtonOptions = WithVariantProps<{\n  tagName?: string\n  href?: string\n} & RouterLinkProps & ButtonHTMLAttributes & Data>;\n"
  },
  {
    "path": "src/types/components/t-card.ts",
    "content": "import { WithVariantPropsAndClassesList, TCardClassesValidKeys, Data } from '@variantjs/core';\nimport { HTMLAttributes } from 'vue';\n\nexport type TCardOptions = WithVariantPropsAndClassesList<{\n  tagName?: string\n  body?: string\n  header?: string\n  footer?: string\n} & HTMLAttributes & Data, TCardClassesValidKeys>;\n"
  },
  {
    "path": "src/types/components/t-checkbox.ts",
    "content": "import { Data, WithVariantProps } from '@variantjs/core';\nimport { InputHTMLAttributes } from 'vue';\nimport { ObjectWithProperties } from '../helpers';\n\n// eslint-disable-next-line @typescript-eslint/ban-types\ntype TCheckboxSimpleValue = string | number | boolean | undefined | null | Date | Function | symbol;\nexport type TCheckboxValue = TCheckboxSimpleValue | TCheckboxSimpleValue[] | ObjectWithProperties<TCheckboxSimpleValue>;\n\nexport type TCheckboxOptions = WithVariantProps<{\n  modelValue?: TCheckboxValue\n} & InputHTMLAttributes & {\n  type?: 'checkbox'\n} & Data>;\n"
  },
  {
    "path": "src/types/components/t-dialog.ts",
    "content": "import {\n  WithVariantPropsAndClassesList, Data, TDialogClassesValidKeys, DialogPreconfirmFn, DialogInputValidatorFn,\n} from '@variantjs/core';\nimport { BodyScrollOptions } from 'body-scroll-lock';\nimport { HTMLAttributes } from 'vue';\n\nexport type TDialogOptions = WithVariantPropsAndClassesList<{\n  type?: string,\n  icon?: string,\n  useSolidIcon?: boolean,\n  rejectOnCancel?: boolean,\n  rejectOnDismiss?: boolean,\n  title?: string,\n  titleTag?: string,\n  text?: string,\n  textTag?: string,\n  cancelButtonText?: string,\n  cancelButtonAriaLabel?: string,\n  okButtonText?: string,\n  okButtonAriaLabel?: string,\n  preConfirm?: DialogPreconfirmFn,\n  name?: string,\n  modelValue?: boolean,\n  dialogAttributes?: HTMLAttributes & Data,\n  tagName?: string\n  clickToClose?: boolean,\n  escToClose?: boolean,\n  focusOnOpen?: boolean,\n  showCloseButton?: boolean,\n  disableBodyScroll?: boolean,\n  bodyScrollLockOptions?: BodyScrollOptions,\n  teleport?: boolean,\n  teleportTo?: string | HTMLElement,\n  // (Prompt only)\n  // Attributes for the text input\n  inputAttributes?: HTMLAttributes & Data,\n  // Type for the prompt input (accepts 'input', 'textarea' ,'select' and 'checkbox')\n  inputType?: 'string',\n  // Function for validate the value of the prompt, receives the prompt value and should return an error message or empty if no errors. It accepts a promise\n  inputValidator?: DialogInputValidatorFn,\n  // Default value of the input\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  inputValue?: any,\n} & HTMLAttributes & Data, TDialogClassesValidKeys>;\n"
  },
  {
    "path": "src/types/components/t-dropdown.ts",
    "content": "import { Placement, Options } from '@popperjs/core';\nimport { WithVariantPropsAndClassesList, TDropdownClassesValidKeys, Data } from '@variantjs/core';\nimport { HTMLAttributes } from 'vue';\n\nexport type TDropdownOptions = WithVariantPropsAndClassesList<{\n  text?: string,\n  disabled?: boolean,\n\n  tagName?: string,\n  dropdownTagName?: string,\n  dropdownAttributes?: Data,\n\n  toggleOnFocus?: boolean,\n  toggleOnClick?: boolean,\n  toggleOnHover?: boolean,\n\n  show?: boolean,\n\n  hideOnLeaveTimeout?: number,\n\n  teleport?: boolean,\n  teleportTo?: string | HTMLElement,\n\n  placement?: Placement,\n  popperOptions?: Options,\n} & HTMLAttributes & Data, TDropdownClassesValidKeys>;\n"
  },
  {
    "path": "src/types/components/t-input-group.ts",
    "content": "import { WithVariantPropsAndClassesList, TInputGroupClassesValidKeys, Data } from '@variantjs/core';\nimport { HTMLAttributes } from 'vue';\n\nexport type TInputGroupValidChilElementsKeys = ('label' | 'default' | 'feedback' | 'description')[];\n\nexport type TInputGroupOptions = WithVariantPropsAndClassesList<{\n  label?: string\n  description?: string\n  feedback?: string\n  body?: string\n  sortedElements?: TInputGroupValidChilElementsKeys,\n  tagName?: string,\n  bodyTagName?: string,\n  labelTagName?: string,\n  feedbackTagName?: string,\n  descriptionTagName?: string,\n} & HTMLAttributes & Data, TInputGroupClassesValidKeys>;\n"
  },
  {
    "path": "src/types/components/t-input.ts",
    "content": "import { Data, WithVariantProps } from '@variantjs/core';\nimport { InputHTMLAttributes } from 'vue';\n\nexport type TInputValue = string | number | string[] | undefined;\n\nexport type TInputOptions = WithVariantProps<{\n  modelValue?: TInputValue,\n} & InputHTMLAttributes & Data>;\n"
  },
  {
    "path": "src/types/components/t-modal.ts",
    "content": "import { WithVariantPropsAndClassesList, Data, TModalClassesValidKeys } from '@variantjs/core';\nimport { BodyScrollOptions } from 'body-scroll-lock';\nimport { HTMLAttributes } from 'vue';\n\nexport type TModalOptions = WithVariantPropsAndClassesList<{\n  name?: string,\n  modelValue?: boolean,\n  modalAttributes?: HTMLAttributes & Data,\n  tagName?: string\n  body?: string\n  header?: string\n  footer?: string\n  clickToClose?: boolean,\n  escToClose?: boolean,\n  focusOnOpen?: boolean,\n  disableBodyScroll?: boolean,\n  bodyScrollLockOptions?: BodyScrollOptions,\n  teleport?: boolean,\n  teleportTo?: string | HTMLElement,\n  noBody?: boolean,\n  hideCloseButton?: boolean,\n} & HTMLAttributes & Data, TModalClassesValidKeys>;\n"
  },
  {
    "path": "src/types/components/t-radio.ts",
    "content": "import { Data, WithVariantProps } from '@variantjs/core';\nimport { InputHTMLAttributes } from 'vue';\nimport { ObjectWithProperties } from '../helpers';\n\n// eslint-disable-next-line @typescript-eslint/ban-types\ntype TRadioSimpleValue = string | number | boolean | undefined | null | Date | Function | symbol;\nexport type TRadioValue = TRadioSimpleValue | TRadioSimpleValue[] | ObjectWithProperties<TRadioSimpleValue>;\n\nexport type TRadioOptions = WithVariantProps<{\n  modelValue?: TRadioValue\n} & InputHTMLAttributes & {\n  type?: 'radio'\n} & Data>;\n"
  },
  {
    "path": "src/types/components/t-rich-select.ts",
    "content": "import {\n  Data, InputOptions, Measure, NormalizedOption, NormalizedOptions, TRichSelectClassesValidKeys, WithVariantPropsAndClassesList,\n} from '@variantjs/core';\nimport { HTMLAttributes } from 'vue';\nimport { Placement, Options } from '@popperjs/core';\nimport { TSelectValue } from './t-select';\nimport { FetchOptionsFn, PreFetchOptionsFn } from '../misc';\n\nexport type MinimumInputLengthTextProp = ((minimumInputLength: number, query?: string) => string) | string;\n\nexport type TRichSelectOptions = WithVariantPropsAndClassesList<{\n  modelValue?: TSelectValue,\n  options?: InputOptions | NormalizedOption[] | NormalizedOptions,\n  multiple?: boolean\n  name?: string,\n  tags?: boolean\n  normalizeOptions?: boolean,\n  valueAttribute?: string,\n  textAttribute?: string,\n  delay?: number,\n  fetchOptions?: FetchOptionsFn,\n  prefetchOptions?: boolean | PreFetchOptionsFn,\n  minimumInputLength?: number,\n  minimumInputLengthText?: MinimumInputLengthTextProp,\n  minimumResultsForSearch?: number,\n  hideSearchBox?: boolean,\n  toggleOnFocus?: boolean,\n  toggleOnClick?: boolean,\n  closeOnSelect?: boolean,\n  selectOnClose?: boolean,\n  clearable?: boolean,\n  disabled?: boolean,\n  placeholder?: string,\n  searchBoxPlaceholder?: string,\n  noResultsText?: string,\n  searchingText?: string,\n  loadingClosedPlaceholder?: string,\n  loadingMoreResultsText?: string,\n  maxHeight?: Measure | null,\n  dropdownPlacement?: Placement,\n  dropdownPopperOptions?: Options,\n  teleport?: boolean,\n  teleportTo?: string | HTMLElement,\n} & HTMLAttributes & Data, TRichSelectClassesValidKeys>;\n"
  },
  {
    "path": "src/types/components/t-select.ts",
    "content": "import {\n  Data, InputOptions, NormalizedOption, NormalizedOptions, WithVariantProps,\n} from '@variantjs/core';\nimport { SelectHTMLAttributes } from 'vue';\nimport { Truthy } from '../misc';\n\n// eslint-disable-next-line @typescript-eslint/ban-types\nexport type TSelectValue = string | number | boolean | undefined | null | Date | Function | symbol | TSelectValue[];\n\nexport type TSelectOptions = WithVariantProps<{\n  modelValue?: TSelectValue,\n  options?: InputOptions | NormalizedOption[] | NormalizedOptions,\n  multiple?: Truthy,\n  normalizeOptions?: boolean,\n  valueAttribute?: string\n  textAttribute?: string\n} & SelectHTMLAttributes & Data>;\n"
  },
  {
    "path": "src/types/components/t-tag.ts",
    "content": "import { Data, WithVariantProps } from '@variantjs/core';\nimport { HTMLAttributes } from 'vue';\n\nexport type TTagOptions = WithVariantProps<{\n  tagName?: string\n  text?: string\n} & HTMLAttributes & Data>;\n"
  },
  {
    "path": "src/types/components/t-textarea.ts",
    "content": "import { Data, WithVariantProps } from '@variantjs/core';\nimport { InputHTMLAttributes } from 'vue';\n\nexport type TTextareaValue = string | number | string[] | undefined;\n\nexport type TTextareaOptions = WithVariantProps<{\n  modelValue?: TTextareaValue,\n} & InputHTMLAttributes & Data>;\n"
  },
  {
    "path": "src/types/components/t-toggle.ts",
    "content": "import { WithVariantPropsAndClassesList, TToggleClassesValidKeys, Data } from '@variantjs/core';\nimport { HTMLAttributes } from 'vue';\nimport { TCheckboxValue } from './t-checkbox';\n\nexport type TToggleValue = TCheckboxValue;\n\nexport type TToggleOptions = WithVariantPropsAndClassesList<{\n  name?: string,\n  modelValue?: TToggleValue,\n  value?: TToggleValue,\n  uncheckedValue?: TToggleValue,\n  checked?: boolean,\n  disabled?: boolean,\n  checkedPlaceholder?: string,\n  uncheckedPlaceholder?: string,\n} & HTMLAttributes & Data, TToggleClassesValidKeys>;\n"
  },
  {
    "path": "src/types/helpers.ts",
    "content": "type ObjectWithProperties<P> = Record<string | number | symbol, P>;\n\ntype KeysOfType<T, TProp> = { [P in keyof T]: T[P] extends TProp? P : never }[keyof T];\n\nexport { ObjectWithProperties, KeysOfType };\n"
  },
  {
    "path": "src/types/index.ts",
    "content": "export { VariantJSConfiguration, VariantJSProps, VariantJSWithClassesListProps } from './variantCore';\nexport { TInputValue, TInputOptions } from './components/t-input';\nexport { TTextareaValue, TTextareaOptions } from './components/t-textarea';\nexport { TRadioValue, TRadioOptions } from './components/t-radio';\nexport { TCheckboxValue, TCheckboxOptions } from './components/t-checkbox';\nexport { TSelectValue, TSelectOptions } from './components/t-select';\nexport { TButtonOptions } from './components/t-button';\nexport { TCardOptions } from './components/t-card';\nexport { TModalOptions } from './components/t-modal';\nexport { TDialogOptions } from './components/t-dialog';\nexport { TTagOptions } from './components/t-tag';\nexport { TAlertOptions } from './components/t-alert';\nexport { TToggleValue, TToggleOptions } from './components/t-toggle';\nexport { TDropdownOptions } from './components/t-dropdown';\nexport { TRichSelectOptions, MinimumInputLengthTextProp } from './components/t-rich-select';\nexport { TInputGroupOptions, TInputGroupValidChilElementsKeys } from './components/t-input-group';\nexport {\n  Truthy, IconProp, FetchOptionsFn, FetchedOptions, PreFetchOptionsFn, PromiseRejectFn,\n} from './misc';\nexport { ObjectWithProperties, KeysOfType } from './helpers';\nexport { EmitterEvents, EmitterFunction, EmitterInterface } from './utils';\nexport { VueRouteAriaCurrentValue, VueRouteRouteLocationRaw } from './vueRouter';\n"
  },
  {
    "path": "src/types/misc.ts",
    "content": "import { Data, InputOptions } from '@variantjs/core';\n\ntype Truthy = boolean | string;\n\n// eslint-disable-next-line @typescript-eslint/ban-types\ntype IconProp = Element | string | (Data & { render?: Function });\n\ntype FetchedOptions = Promise<{\n  results: InputOptions;\n  hasMorePages?: boolean;\n}>;\n\ntype FetchOptionsFn = (query?: string, nextPage?: number) => FetchedOptions;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype PreFetchOptionsFn = (currentValue?: any) => Promise<InputOptions>;\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype PromiseRejectFn = ((reason?: any) => void);\n\nexport {\n  Truthy, IconProp, FetchOptionsFn, FetchedOptions, PromiseRejectFn, PreFetchOptionsFn,\n};\n"
  },
  {
    "path": "src/types/utils.ts",
    "content": "/* eslint-disable @typescript-eslint/no-explicit-any */\ntype EmitterFunction = (...args : any[]) => void;\n\ntype EmitterEvents = {\n  [key: string]: EmitterFunction[]\n};\n\ninterface EmitterInterface {\n  on(name: keyof EmitterEvents, callback: EmitterFunction): void;\n  once(name: keyof EmitterEvents, callback: EmitterFunction): void;\n  emit(name: keyof EmitterEvents, ...args: any[]): void;\n  emit(name: keyof EmitterEvents, ...args: any[]): void;\n  off(name: keyof EmitterEvents, callback: EmitterFunction): void;\n}\n\nexport { EmitterEvents, EmitterFunction, EmitterInterface };\n"
  },
  {
    "path": "src/types/variantCore.ts",
    "content": "import {\n  CSSRawClassesList,\n  CSSClass, Variants, VariantsWithClassesList, WithVariantProps, WithVariantPropsAndClassesList, Data,\n} from '@variantjs/core';\n\nimport { ComponentPropsOptions, PropType } from 'vue';\nimport { TButtonOptions } from './components/t-button';\nimport { TCardOptions } from './components/t-card';\nimport { TCheckboxOptions } from './components/t-checkbox';\nimport { TInputOptions } from './components/t-input';\nimport { TInputGroupOptions } from './components/t-input-group';\nimport { TRadioOptions } from './components/t-radio';\nimport { TSelectOptions } from './components/t-select';\nimport { TTagOptions } from './components/t-tag';\nimport { TTextareaOptions } from './components/t-textarea';\n\ntype VariantJSProps<ComponentOptions extends WithVariantProps<Data> = {\n  classes?: CSSClass;\n  fixedClasses?: CSSClass;\n  variants?: Variants<Data>;\n  variant?: string;\n  class?: string;\n}, PropsOptions extends Readonly<ComponentPropsOptions> = {\n  classes: {\n    type: PropType<CSSClass>;\n    default: undefined;\n  },\n  fixedClasses: {\n    type: PropType<CSSClass>;\n    default: undefined;\n  },\n  variants: {\n    type: PropType<Variants<ComponentOptions>>;\n    default: undefined;\n  },\n  variant: {\n    type:PropType<string | undefined>;\n    default: undefined;\n  },\n}> = PropsOptions & {\n  classes: {\n    type: PropType<CSSClass>;\n    default: undefined;\n  },\n  fixedClasses: {\n    type: PropType<CSSClass>;\n    default: undefined;\n  },\n  variants: {\n    type: PropType<Variants<ComponentOptions>>;\n    default: undefined;\n  },\n  variant: {\n    type:PropType<string | undefined>;\n    default: undefined;\n  },\n};\n\ntype VariantJSWithClassesListProps<\n  ClassesKeys extends string,\n  ComponentOptions extends WithVariantPropsAndClassesList<Data, ClassesKeys> = WithVariantPropsAndClassesList<Data, ClassesKeys>,\n  PropsOptions extends Readonly<ComponentPropsOptions> = {\n    classes: {\n      type: PropType<CSSRawClassesList<ClassesKeys>>;\n      default: undefined;\n    },\n    fixedClasses: {\n      type: PropType<CSSRawClassesList<ClassesKeys>>;\n      default: undefined;\n    },\n    variants: {\n      type: PropType<VariantsWithClassesList<ComponentOptions, ClassesKeys>>;\n      default: undefined;\n    },\n    variant: {\n      type:PropType<string | undefined>;\n      default: undefined;\n    },\n  }> = PropsOptions & {\n    classes: {\n      type: PropType<CSSRawClassesList<ClassesKeys>>;\n      default: undefined;\n    },\n    fixedClasses: {\n      type: PropType<CSSRawClassesList<ClassesKeys>>;\n      default: undefined;\n    },\n    variants: {\n      type: PropType<VariantsWithClassesList<ComponentOptions, ClassesKeys>>;\n      default: undefined;\n    },\n    variant: {\n      type:PropType<string | undefined>;\n      default: undefined;\n    },\n  };\n\ntype VariantJSConfiguration = {\n  TInput?: TInputOptions\n  TSelect?: TSelectOptions\n  TRadio?: TRadioOptions\n  TCheckbox?: TCheckboxOptions\n  TButton?: TButtonOptions\n  TTextarea?: TTextareaOptions\n  TTag?: TTagOptions\n  TCard?: TCardOptions\n  TInputGroup?: TInputGroupOptions,\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  [key: string]: any\n};\n\nexport { VariantJSConfiguration, VariantJSProps, VariantJSWithClassesListProps };\n"
  },
  {
    "path": "src/types/vueRouter.ts",
    "content": "// Copied from the types on vue/node_modules/vue-router/dist/vue-router.d.ts\n// so we dont need to add any extra dependency\n\ntype RouteParamValue = string;\n\ntype RouteParamValueRaw = RouteParamValue | number;\n\ntype RouteParamsRaw = Record<string, RouteParamValueRaw | RouteParamValueRaw[]>;\n\ntype RouteRecordName = string | symbol;\n\ninterface LocationAsRelativeRaw {\n  name?: RouteRecordName;\n  params?: RouteParamsRaw;\n}\n\ntype HistoryStateArray = Array<HistoryStateValue>;\n\ntype HistoryStateValue = string | number | boolean | null | undefined | HistoryState | HistoryStateArray;\n\n/**\n * Allowed HTML history.state\n */\ninterface HistoryState {\n  [x: number]: HistoryStateValue;\n  [x: string]: HistoryStateValue;\n}\n\ninterface RouteLocationOptions {\n  /**\n   * Replace the entry in the history instead of pushing a new entry\n   */\n  replace?: boolean;\n  /**\n   * Triggers the navigation even if the location is the same as the current one\n   */\n  force?: boolean;\n  /**\n   * State to save using the History API. This cannot contain any reactive\n   * values and some primitives like Symbols are forbidden. More info at\n   * https://developer.mozilla.org/en-US/docs/Web/API/History/state\n   */\n  state?: HistoryState;\n}\n\ninterface LocationAsPath {\n  path: string;\n}\n\ntype LocationQueryValue = string | null;\n\ntype LocationQueryValueRaw = LocationQueryValue | number | undefined;\n\ntype LocationQueryRaw = Record<string | number, LocationQueryValueRaw | LocationQueryValueRaw[]>;\n\ninterface RouteQueryAndHash {\n  query?: LocationQueryRaw;\n  hash?: string;\n}\n\ntype VueRouteRouteLocationRaw = string | (RouteQueryAndHash & LocationAsPath & RouteLocationOptions) | (RouteQueryAndHash & LocationAsRelativeRaw & RouteLocationOptions);\ntype VueRouteAriaCurrentValue = 'page' | 'step' | 'location' | 'date' | 'time' | 'true' | 'false' | undefined;\n\nexport { VueRouteAriaCurrentValue, VueRouteRouteLocationRaw };\n"
  },
  {
    "path": "src/use/useActivableOption.ts",
    "content": "import { isEqual, NormalizedOption, normalizedOptionIsDisabled } from '@variantjs/core';\nimport {\n  computed, ComputedRef, Ref, ref, watch,\n} from 'vue';\n\nexport default function useActivableOption(\n  options: ComputedRef<NormalizedOption[]>,\n  localValue: Ref,\n): {\n    activeOption: Ref<NormalizedOption | null>,\n    initActiveOption: () => void,\n    optionIsActive: (option: NormalizedOption) => boolean,\n    setActiveOption: (option: NormalizedOption) => void,\n    setNextOptionActive: () => void,\n    setPrevOptionActive: () => void,\n  } {\n  const getActiveOption = (): NormalizedOption | null => {\n    const selectedOption = options.value.find((option: NormalizedOption) => isEqual(option.value, localValue.value) && !normalizedOptionIsDisabled(option));\n\n    if (selectedOption !== undefined) {\n      return selectedOption;\n    }\n\n    if (options.value.length > 0) {\n      return options.value.find((option) => !normalizedOptionIsDisabled(option)) || null;\n    }\n\n    return null;\n  };\n\n  const activeOption = ref<NormalizedOption | null>(getActiveOption());\n\n  const activeOptionIndex = computed((): number => {\n    if (activeOption.value === null) {\n      return 0;\n    }\n\n    const index = options.value.findIndex((option) => isEqual(option.value, (activeOption.value as NormalizedOption).value));\n\n    return index < 0 ? 0 : index;\n  });\n\n  const optionIsActive = (option: NormalizedOption): boolean => (activeOption.value === null ? false : isEqual(activeOption.value.value, option.value));\n\n  const setActiveOption = (option: NormalizedOption): void => {\n    activeOption.value = option;\n  };\n\n  const setNextOptionActive = (): void => {\n    let newActiveOption: NormalizedOption | undefined;\n    let nextIndex = activeOptionIndex.value + 1;\n\n    while (nextIndex < options.value.length && newActiveOption === undefined) {\n      const option = options.value[nextIndex];\n      const optionIsDisabled = normalizedOptionIsDisabled(option);\n      if (!optionIsDisabled) {\n        newActiveOption = option;\n      }\n      nextIndex += 1;\n    }\n\n    if (newActiveOption) {\n      setActiveOption(newActiveOption);\n    }\n  };\n\n  const setPrevOptionActive = (): void => {\n    let newActiveOption: NormalizedOption | undefined;\n    let nextIndex = activeOptionIndex.value - 1;\n\n    while (nextIndex >= 0 && newActiveOption === undefined) {\n      const option = options.value[nextIndex];\n      const optionIsDisabled = normalizedOptionIsDisabled(option);\n      if (!optionIsDisabled) {\n        newActiveOption = option;\n      }\n      nextIndex -= 1;\n    }\n\n    if (newActiveOption) {\n      setActiveOption(newActiveOption);\n    }\n  };\n\n  const initActiveOption = (): void => {\n    activeOption.value = getActiveOption();\n  };\n\n  watch(options, (newOptions: NormalizedOption[], oldOptions: NormalizedOption[]) => {\n    const firstNewOption = newOptions.find((o) => !oldOptions.includes(o) && !normalizedOptionIsDisabled(o));\n\n    if (firstNewOption) {\n      setActiveOption(firstNewOption);\n    } else {\n      initActiveOption();\n    }\n  });\n\n  return {\n    activeOption,\n    initActiveOption,\n    optionIsActive,\n    setActiveOption,\n    setNextOptionActive,\n    setPrevOptionActive,\n  };\n}\n"
  },
  {
    "path": "src/use/useConfiguration.ts",
    "content": "import {\n  computed, inject, camelize, getCurrentInstance, ComponentInternalInstance, ComputedRef, watch, reactive,\n} from 'vue';\nimport {\n  Data, get, isEqual, isPrimitive, parseVariant, pick,\n} from '@variantjs/core';\nimport { VariantJSConfiguration } from '../types';\n\nexport const extractDefinedProps = (vm: ComponentInternalInstance): string[] => {\n  const validProps = Object.keys(vm.props);\n\n  const definedProps = Object.keys(vm.vnode.props || {})\n    .map((propName) => camelize(propName))\n    .filter((propName) => validProps.includes(propName) && propName !== 'modelValue');\n\n  return definedProps;\n};\n\nexport function useAttributes<ComponentOptions extends Data>(configuration: ComponentOptions): Data {\n  const vm = getCurrentInstance()!;\n\n  const computedAttributes: ComputedRef<Data> = computed<Data>(():Data => {\n    const availableProps = Object.keys(vm.props);\n\n    return pick(configuration, (value, key) => isPrimitive(value) && !availableProps.includes(String(key)));\n  });\n\n  const attributes = reactive<Data>(computedAttributes.value);\n\n  watch(computedAttributes, (newValue) => {\n    Object.keys(newValue).forEach((key) => {\n      if (!isEqual(attributes[key], newValue[key])) {\n        attributes[key] = newValue[key];\n      }\n    });\n  });\n\n  return attributes;\n}\n\nexport function useConfigurationParts<ComponentOptions extends Data>(): {\n  componentGlobalConfiguration?: ComponentOptions\n  propsValues: ComputedRef<Data>\n} {\n  const vm = getCurrentInstance()!;\n\n  const variantGlobalConfiguration = inject<VariantJSConfiguration>('configuration', {});\n\n  const componentGlobalConfiguration = get<VariantJSConfiguration, ComponentOptions>(variantGlobalConfiguration, vm?.type.name as keyof VariantJSConfiguration, {});\n\n  const propsValues = computed(() => {\n    const values: Data = {};\n\n    extractDefinedProps(vm).forEach((attributeName) => {\n      const normalizedAttribute = camelize(attributeName);\n      values[normalizedAttribute] = vm.props[normalizedAttribute];\n    });\n\n    return values;\n  });\n\n  return {\n    componentGlobalConfiguration,\n    propsValues: propsValues as ComputedRef<Data>,\n  };\n}\n\nexport default function useConfiguration<ComponentOptions extends Data>(defaultConfiguration: ComponentOptions): {\n  configuration: ComponentOptions,\n  attributes: Data,\n} {\n  const vm = getCurrentInstance()!;\n\n  const { propsValues, componentGlobalConfiguration } = useConfigurationParts<ComponentOptions>();\n\n  const computedConfiguration = computed(() => {\n    const props = { ...vm.props };\n    delete props.modelValue;\n    return {\n      ...props,\n      ...parseVariant(\n        propsValues.value,\n        componentGlobalConfiguration,\n        defaultConfiguration,\n      ),\n    };\n  });\n\n  const configuration = reactive(computedConfiguration.value);\n\n  watch(computedConfiguration, (newValue) => {\n    Object.keys(newValue).forEach((key) => {\n      configuration[key] = newValue[key];\n    });\n  });\n\n  const attributes = useAttributes(configuration);\n\n  return {\n    configuration: configuration as ComponentOptions,\n    attributes,\n  };\n}\n"
  },
  {
    "path": "src/use/useConfigurationWithClassesList.ts",
    "content": "import {\n  computed, getCurrentInstance, reactive, watch,\n} from 'vue';\nimport { Data, parseVariantWithClassesList } from '@variantjs/core';\nimport { useAttributes, useConfigurationParts } from './useConfiguration';\n\nexport default function useConfigurationWithClassesList<ComponentOptions extends Data>(defaultConfiguration: ComponentOptions, classesListKeys: string[]): {\n  configuration: ComponentOptions,\n  attributes: Data,\n} {\n  const vm = getCurrentInstance()!;\n\n  const { propsValues, componentGlobalConfiguration } = useConfigurationParts<ComponentOptions>();\n\n  const computedConfiguration = computed(() => ({\n    ...vm.props,\n    ...parseVariantWithClassesList(\n      propsValues.value,\n      classesListKeys,\n      componentGlobalConfiguration,\n      defaultConfiguration,\n    ),\n  }));\n\n  const configuration = reactive(computedConfiguration.value);\n\n  watch(computedConfiguration, (newValue) => {\n    Object.keys(newValue).forEach((key) => {\n      configuration[key] = newValue[key];\n    });\n  });\n\n  const attributes = useAttributes(configuration);\n\n  return {\n    configuration: configuration as ComponentOptions,\n    attributes,\n  };\n}\n"
  },
  {
    "path": "src/use/useFetchsOptions.ts",
    "content": "import {\n  debounce, filterOptions, flattenOptions, InputOptions, NormalizedOption, NormalizedOptions, normalizeOptions,\n} from '@variantjs/core';\nimport {\n  computed, Ref, ref, ComputedRef, getCurrentInstance, watch,\n} from 'vue';\nimport {\n  FetchedOptions, FetchOptionsFn, MinimumInputLengthTextProp, PreFetchOptionsFn,\n} from '../types';\n\nexport default function useFetchsOptions(\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  localValue: Ref<any>,\n  options: Ref<InputOptions | undefined>,\n  textAttribute: Ref<string | undefined>,\n  valueAttribute: Ref<string | undefined>,\n  normalize: Ref<boolean>,\n  searchQuery: Ref<string | undefined>,\n  fetchFn: Ref<FetchOptionsFn | undefined>,\n  prefetchFn: Ref<boolean | PreFetchOptionsFn>,\n  fetchDelay: Ref<number | undefined>,\n  fetchMinimumInputLength: Ref<number | undefined>,\n  fetchMinimumInputLengthText: Ref<MinimumInputLengthTextProp>,\n): {\n\n    normalizedOptions: ComputedRef<NormalizedOptions>\n    flattenedOptions: ComputedRef<NormalizedOption[]>\n    fetchsOptions: ComputedRef<boolean>,\n    needsMoreCharsToFetch: ComputedRef<boolean>,\n    needsMoreCharsMessage: ComputedRef<string>,\n    fetchingOptions: Ref<boolean>,\n    fetchingMoreOptions: Ref<boolean>,\n    fetchedOptionsHaveMorePages: Ref<boolean>,\n    optionsWereFetched: Ref<boolean>,\n    fetchOptions: () => void,\n    prefetchOptions: () => void,\n    fetchMoreOptions: () => void,\n    fetchOptionsCancel: () => void,\n  } {\n  const { emit } = getCurrentInstance()!;\n\n  const getNormalizedOptions = (rawOptions: InputOptions): NormalizedOptions => (normalize.value\n    ? normalizeOptions(rawOptions, textAttribute.value, valueAttribute.value)\n    : rawOptions as NormalizedOptions);\n\n  const fetchedOptions = ref<NormalizedOptions>(getNormalizedOptions(options.value || []));\n\n  watch(options, () => {\n    fetchedOptions.value = getNormalizedOptions(options.value || []);\n  });\n\n  const optionsWereFetched = ref<boolean>(false);\n\n  const normalizedOptions = computed<NormalizedOptions>(() => {\n    if (typeof fetchFn.value !== 'function' && typeof prefetchFn.value !== 'function') {\n      const normalized = getNormalizedOptions(options.value || []);\n\n      if (searchQuery.value) {\n        return filterOptions(normalized, searchQuery.value);\n      }\n\n      return normalized;\n    }\n\n    return fetchedOptions.value;\n  });\n\n  const flattenedOptions = computed<NormalizedOption[]>(() => flattenOptions(normalizedOptions.value));\n\n  const fetchsOptions = computed<boolean>(() => fetchFn.value !== undefined);\n\n  const needsMoreCharsToFetch = computed<boolean>(() => {\n    if (!fetchsOptions.value) {\n      return false;\n    }\n\n    if (!fetchMinimumInputLength.value) {\n      return false;\n    }\n\n    return !searchQuery.value || searchQuery.value.length < fetchMinimumInputLength.value;\n  });\n\n  const fetchNextPage = ref<number | undefined>(undefined);\n\n  const fetchingOptions = ref<boolean>(false);\n\n  const fetchingMoreOptions = ref<boolean>(false);\n\n  const fetchedOptionsHaveMorePages = computed<boolean>(() => fetchNextPage.value !== undefined);\n\n  const fetchOptionsFn = ([nextPage]: [number | undefined]): void => {\n    fetchFn.value!(searchQuery.value, nextPage)\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      .then((response: FetchedOptions | any) => {\n        if (typeof response === 'object' && Object.prototype.hasOwnProperty.call(response, 'results')) {\n          const {\n            results,\n            hasMorePages,\n          } = response;\n\n          if (!Array.isArray(results) && results !== undefined && typeof results !== 'object') {\n            throw new Error(`Response.results must be an array or object, got ${typeof results}`);\n          }\n\n          if (nextPage !== undefined && nextPage >= 2) {\n            fetchedOptions.value = fetchedOptions.value.concat(getNormalizedOptions(results));\n          } else {\n            fetchedOptions.value = getNormalizedOptions(results);\n          }\n\n          if (hasMorePages) {\n            fetchNextPage.value = fetchNextPage.value === undefined ? 2 : fetchNextPage.value + 1;\n          } else {\n            fetchNextPage.value = undefined;\n          }\n        } else {\n          throw new Error('Options response must be an object with `results` property.');\n        }\n\n        optionsWereFetched.value = true;\n\n        emit('fetch-options-success', response);\n      }).catch((error) => {\n        emit('fetch-options-error', error);\n      }).then(() => {\n        fetchingOptions.value = false;\n        fetchingMoreOptions.value = false;\n      });\n  };\n\n  const debouncedFetchOptions = debounce(fetchOptionsFn, fetchDelay.value);\n\n  const fetchOptionsCancel = () => {\n    debouncedFetchOptions.cancel();\n    fetchingOptions.value = false;\n    fetchingMoreOptions.value = false;\n  };\n\n  const fetchOptions = (nextPage?: number) => {\n    if (!fetchsOptions.value) {\n      fetchOptionsCancel();\n      return;\n    }\n\n    if (nextPage !== undefined && nextPage >= 2) {\n      fetchingMoreOptions.value = true;\n    } else {\n      fetchingOptions.value = true;\n    }\n\n    debouncedFetchOptions(nextPage);\n  };\n\n  const fetchMoreOptions = () => {\n    fetchOptions(fetchNextPage.value);\n  };\n\n  watch(searchQuery, () => {\n    if (!fetchsOptions.value || needsMoreCharsToFetch.value) {\n      return;\n    }\n\n    optionsWereFetched.value = false;\n\n    fetchOptions();\n  });\n\n  const needsMoreCharsMessage = computed<string>((): string => {\n    if (typeof fetchMinimumInputLengthText.value === 'string') {\n      return fetchMinimumInputLengthText.value;\n    }\n\n    return fetchMinimumInputLengthText.value(fetchMinimumInputLength.value!, searchQuery.value);\n  });\n\n  const prefetchOptions = (): void => {\n    if (typeof prefetchFn.value !== 'function') {\n      fetchOptions();\n      return;\n    }\n\n    fetchingOptions.value = true;\n\n    prefetchFn.value!(localValue.value)\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      .then((results: InputOptions | any) => {\n        if (!Array.isArray(results) && results !== undefined && typeof results !== 'object') {\n          throw new Error(`Response must be an array or object, got ${typeof results}`);\n        }\n\n        fetchedOptions.value = getNormalizedOptions(results);\n\n        optionsWereFetched.value = true;\n\n        emit('fetch-options-success', results);\n      }).catch((error) => {\n        emit('fetch-options-error', error);\n      }).then(() => {\n        fetchingOptions.value = false;\n      });\n  };\n\n  return {\n    normalizedOptions,\n    flattenedOptions,\n    fetchsOptions,\n    needsMoreCharsToFetch,\n    needsMoreCharsMessage,\n    fetchingOptions,\n    fetchingMoreOptions,\n    fetchedOptionsHaveMorePages,\n    optionsWereFetched,\n    fetchOptions,\n    prefetchOptions,\n    fetchMoreOptions,\n    fetchOptionsCancel,\n  };\n}\n"
  },
  {
    "path": "src/use/useInjectsClassesList.ts",
    "content": "import { CSSClassesList } from '@variantjs/core';\nimport { ComputedRef, computed } from 'vue';\nimport useInjectsConfiguration from './useInjectsConfiguration';\n\nexport default function useInjectsClassesList(): ComputedRef<CSSClassesList> {\n  const configuration = useInjectsConfiguration();\n\n  return computed<CSSClassesList>((): CSSClassesList => configuration.classesList || {});\n}\n"
  },
  {
    "path": "src/use/useInjectsClassesListClass.ts",
    "content": "import { CSSClass, get } from '@variantjs/core';\nimport { ComputedRef, computed } from 'vue';\nimport useInjectsConfiguration from './useInjectsConfiguration';\n\nexport default function useInjectsClassesListClass(property: string): ComputedRef<CSSClass> {\n  const configuration = useInjectsConfiguration();\n\n  return computed<CSSClass>((): CSSClass => get(configuration.classesList, property, ''));\n}\n"
  },
  {
    "path": "src/use/useInjectsConfiguration.ts",
    "content": "import { Data, WithVariantPropsAndClassesList } from '@variantjs/core';\nimport { inject } from 'vue';\n\nexport default function useInjectsConfiguration<P extends WithVariantPropsAndClassesList<Data, string>>(): P {\n  return inject<P>('configuration', {} as P);\n}\n"
  },
  {
    "path": "src/use/useMulipleableVModel.ts",
    "content": "import { Data } from '@variantjs/core';\nimport {\n  computed, ref, getCurrentInstance, Ref, watch,\n} from 'vue';\n\nexport default function useMulipleableVModel<P extends Data, K extends keyof P, C extends Data>(\n  props: P,\n  key: K,\n  configuration?: C,\n): {\n    localValue: Ref<P[K]>;\n    clearValue: () => void\n  } {\n  const vm = getCurrentInstance();\n\n  const isMultiple = computed<boolean>((): boolean => (configuration === undefined ? false : configuration.multiple !== null && configuration.multiple !== undefined && configuration.multiple !== false));\n\n  const getDefaultValue = (): P[K] => {\n    if (isMultiple.value) {\n      return [] as P[K];\n    }\n\n    return undefined as P[K];\n  };\n\n  const initialValue = props[key];\n\n  const localValue = ref(initialValue === undefined ? getDefaultValue() : initialValue) as Ref<P[K]>;\n\n  watch(localValue, (value) => {\n    vm?.emit(`update:${key}`, value);\n  });\n\n  watch(() => props[key], (value) => {\n    localValue.value = value;\n  });\n\n  const clearValue = () : void => {\n    localValue.value = getDefaultValue();\n  };\n\n  watch(isMultiple, () => {\n    clearValue();\n  });\n\n  return {\n    localValue,\n    clearValue,\n  };\n}\n"
  },
  {
    "path": "src/use/useMultioptions.ts",
    "content": "import {\n  flattenOptions,\n  InputOptions,\n  NormalizedOption,\n  NormalizedOptions,\n  normalizeOptions,\n} from '@variantjs/core';\nimport { computed, ComputedRef, Ref } from 'vue';\n\nexport default function useMultioptions(\n  options: Ref<InputOptions | undefined>,\n  textAttribute: Ref<string | undefined>,\n  valueAttribute: Ref<string | undefined>,\n  normalize: Ref<boolean>,\n): {\n    normalizedOptions: ComputedRef<NormalizedOptions>\n    flattenedOptions: ComputedRef<NormalizedOption[]>\n  } {\n  const normalizedOptions = computed<NormalizedOptions>(() => {\n    if (!normalize.value) {\n      return options.value as NormalizedOptions;\n    }\n\n    return normalizeOptions(\n      options.value,\n      textAttribute.value,\n      valueAttribute.value,\n    );\n  });\n\n  // Flattened array with all posible options\n  const flattenedOptions = computed((): NormalizedOption[] => flattenOptions(normalizedOptions.value));\n\n  return {\n    normalizedOptions,\n    flattenedOptions,\n  };\n}\n"
  },
  {
    "path": "src/use/useSelectableOption.ts",
    "content": "/* eslint-disable no-param-reassign */\nimport {\n  addToArray, isEqual, NormalizedOption, substractFromArray,\n} from '@variantjs/core';\nimport {\n  computed, ComputedRef, Ref, ref, watch,\n} from 'vue';\n\ntype SelectedOption = NormalizedOption | NormalizedOption[] | undefined;\n\nexport default function useSelectableOption(\n  options: Ref<NormalizedOption[]>,\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  localValue: Ref<any>,\n  multiple: Ref<boolean>,\n): {\n    selectedOption: Ref<SelectedOption>,\n    hasSelectedOption: ComputedRef<boolean>,\n    selectOption: (option: NormalizedOption) => void,\n    toggleOption: (option: NormalizedOption) => void,\n    optionIsSelected: (option: NormalizedOption) => boolean,\n  } {\n  const optionIsSelected = (option: NormalizedOption): boolean => {\n    if (multiple.value === true) {\n      return Array.isArray(localValue.value)\n          && localValue.value.some((value) => isEqual(value, option.value));\n    }\n\n    return isEqual(localValue.value, option.value);\n  };\n\n  const getSelectedOption = (currentSelectedOption?: SelectedOption): SelectedOption => {\n    let allOptions: NormalizedOption[] = options.value;\n\n    // If the option is part of the current selected option is desired to use\n    // those option since its possible that the options is not in the list\n    // For example: an option that was selected from an ajax list but was removed\n    if (Array.isArray(currentSelectedOption)) {\n      allOptions = allOptions\n        // Remove the options that are also on the current selected option list\n        .filter((option) => !currentSelectedOption.some((selectedOption) => isEqual(selectedOption.value, option.value)))\n        // Concat the current selected option list\n        .concat(currentSelectedOption);\n    } else if (currentSelectedOption !== undefined) {\n      allOptions = allOptions\n        // Remove the selected option if already exists in the list so it\n        // can be replaced with the selected option\n        .filter((option) => !isEqual(currentSelectedOption.value, option.value))\n        .concat([currentSelectedOption]);\n    }\n\n    if (multiple.value === true) {\n      if (Array.isArray(localValue.value)) {\n        return allOptions.filter((option) => optionIsSelected(option));\n      }\n\n      return [];\n    }\n\n    return allOptions.find((option) => optionIsSelected(option));\n  };\n\n  const selectedOption = ref<SelectedOption>(getSelectedOption());\n\n  const selectOption = (option: NormalizedOption): void => {\n    if (optionIsSelected(option)) {\n      return;\n    }\n\n    if (multiple.value === true) {\n      if (Array.isArray(localValue.value)) {\n        localValue.value = addToArray(localValue.value, option.value);\n        selectedOption.value = addToArray(selectedOption.value, option);\n      } else {\n        localValue.value = [option.value];\n        selectedOption.value = [option];\n      }\n    } else {\n      localValue.value = option.value;\n      selectedOption.value = option;\n    }\n  };\n\n  const toggleOption = (option: NormalizedOption): void => {\n    if (optionIsSelected(option)) {\n      if (multiple.value === true) {\n        localValue.value = substractFromArray(localValue.value, option.value);\n      } else {\n        localValue.value = undefined;\n      }\n    } else if (multiple.value === true) {\n      if (Array.isArray(localValue.value)) {\n        localValue.value = addToArray(localValue.value, option.value);\n      } else {\n        localValue.value = [option.value];\n      }\n    } else {\n      localValue.value = option.value;\n    }\n  };\n\n  watch([options, localValue], () => {\n    selectedOption.value = getSelectedOption(selectedOption.value);\n  });\n\n  const hasSelectedOption = computed((): boolean => {\n    if (multiple.value === true) {\n      return (selectedOption.value as NormalizedOption[]).length > 0;\n    }\n\n    return selectedOption.value !== undefined;\n  });\n\n  return {\n    selectedOption,\n    hasSelectedOption,\n    selectOption,\n    toggleOption,\n    optionIsSelected,\n  };\n}\n"
  },
  {
    "path": "src/use/useVModel.ts",
    "content": "import { Data } from '@variantjs/core';\nimport {\n  getCurrentInstance, Ref, watch, ref,\n} from 'vue';\n\nexport default function useVModel<P extends Data, K extends keyof P>(\n  props: P,\n  key: K,\n): Ref<P[K]> {\n  const vm = getCurrentInstance();\n\n  const localValue = ref(props[key]) as Ref<P[K]>;\n\n  watch(localValue, (value) => {\n    vm?.emit(`update:${key}`, value);\n  });\n\n  watch(() => props[key], (value) => {\n    localValue.value = value;\n  });\n\n  return localValue;\n}\n"
  },
  {
    "path": "src/utils/createDialogProgramatically.ts",
    "content": "import { DialogResponse, DialogType } from '@variantjs/core';\nimport { createApp } from 'vue';\nimport { TDialogOptions } from '../types/components/t-dialog';\nimport { VariantJSConfiguration } from '../types/variantCore';\n\nimport TDialog from '../components/TDialog.vue';\n\nconst createDialogProgramatically = (configuration: VariantJSConfiguration, type: DialogType, titleOrDialogOptions: TDialogOptions | string, text?: string, icon?: string) : Promise<DialogResponse> => {\n  const { props } = TDialog;\n\n  if (typeof titleOrDialogOptions === 'string') {\n    props.title.default = titleOrDialogOptions;\n  } else {\n    Object.keys(titleOrDialogOptions).forEach((key) => {\n      props[key].default = titleOrDialogOptions[key];\n    });\n  }\n\n  if (typeof text === 'string') {\n    props.text.default = text;\n  }\n\n  if (typeof icon === 'string') {\n    props.icon.default = icon;\n  }\n\n  props.type.default = type;\n\n  const instance = createApp(TDialog);\n\n  instance.provide('configuration', configuration);\n\n  const dialogInstance = instance.mount(document.createElement('div'));\n\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  const promise = (dialogInstance as any).show() as Promise<DialogResponse>;\n\n  return promise\n    .then((response) => {\n      instance.unmount();\n\n      return Promise.resolve(response);\n    })\n    .catch((error) => {\n      instance.unmount();\n\n      return Promise.reject(error);\n    });\n};\n\nexport default createDialogProgramatically;\n"
  },
  {
    "path": "src/utils/emitter.ts",
    "content": "/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { EmitterEvents, EmitterFunction, EmitterInterface } from '../types';\n\nexport class Emitter implements EmitterInterface {\n  /* eslint-disable tree-shaking/no-side-effects-in-initialization */\n  private events: EmitterEvents = {};\n\n  on(name: keyof EmitterEvents, callback: EmitterFunction): void {\n    if (this.events[name] === undefined) {\n      this.events[name] = [callback];\n    } else {\n      this.events[name].push(callback);\n    }\n  }\n\n  once(name: keyof EmitterEvents, callback: EmitterFunction): void {\n    const listener = (...args: any[]) => {\n      callback(...args);\n      this.off(name, listener);\n    };\n\n    return this.on(name, listener);\n  }\n\n  emit(name: keyof EmitterEvents, ...args: any[]): void {\n    const events = this.events[name];\n\n    if (events === undefined) {\n      return;\n    }\n\n    events.forEach((callback) => {\n      callback(...args);\n    });\n  }\n\n  off(name: keyof EmitterEvents, callback: EmitterFunction): void {\n    const events = this.events[name];\n\n    if (events === undefined) {\n      return;\n    }\n\n    const index = events.findIndex((c) => c === callback);\n\n    if (index < 0) {\n      return;\n    }\n\n    events.splice(index, 1);\n    this.events[name] = events;\n  }\n}\n"
  },
  {
    "path": "src/utils/getVariantProps.ts",
    "content": "import {\n  CSSClass, CSSRawClassesList, Data, Variants, VariantsWithClassesList,\n} from '@variantjs/core';\n\nimport { PropType } from 'vue';\nimport { VariantJSProps, VariantJSWithClassesListProps } from '../types';\n\nconst getVariantProps = <ComponentOptions extends Data>() : VariantJSProps => ({\n  classes: {\n    type: [String, Array, Object] as PropType<CSSClass>,\n    default: undefined,\n  },\n  fixedClasses: {\n    type: [String, Array, Object] as PropType<CSSClass>,\n    default: undefined,\n  },\n  variants: {\n    type: Object as PropType<Variants<ComponentOptions>>,\n    default: undefined,\n  },\n  variant: {\n    type: String as PropType<string | undefined>,\n    default: undefined,\n  },\n});\n\nconst getVariantPropsWithClassesList = <ComponentOptions extends Data, ClassesKeys extends string>() : VariantJSWithClassesListProps<ClassesKeys> => ({\n  classes: {\n    type: [String, Array, Object] as PropType<CSSRawClassesList<ClassesKeys>>,\n    default: undefined,\n  },\n  fixedClasses: {\n    type: [String, Array, Object] as PropType<CSSRawClassesList<ClassesKeys>>,\n    default: undefined,\n  },\n  variants: {\n    type: Object as PropType<VariantsWithClassesList<ComponentOptions, ClassesKeys>>,\n    default: undefined,\n  },\n  variant: {\n    type: String as PropType<string | undefined>,\n    default: undefined,\n  },\n});\n\nexport { getVariantProps, getVariantPropsWithClassesList };\n"
  },
  {
    "path": "src/utils/popper.ts",
    "content": "import { Modifier, ModifierArguments } from '@popperjs/core';\nimport { Data } from '@variantjs/core';\n\nconst sameWidthModifier: Modifier<'sameWidth', Data> = {\n  name: 'sameWidth',\n  enabled: true,\n  phase: 'beforeWrite',\n  requires: ['computeStyles'],\n  fn: (options: ModifierArguments<Data>): void => {\n    const { state } = options;\n    state.styles.popper.width = `${state.rects.reference.width}px`;\n  },\n  effect: (options: ModifierArguments<Data>): void => {\n    const { state } = options;\n    const reference = state.elements.reference as HTMLElement;\n    state.elements.popper.style.width = `${reference.offsetWidth}px`;\n  },\n};\n\nexport { sameWidthModifier };\n"
  },
  {
    "path": "src/utils/svgToVueComponent.ts",
    "content": "import { Data } from '@variantjs/core';\nimport { h, VNode, VNodeProps } from 'vue';\n\nconst icons: {\n  [key: string]: VNode\n} = {};\n\nexport const svgToVueComponent = (el: Element | string, deep = 0): VNode => {\n  let iconAsString: string | null = null;\n\n  if (deep === 0) {\n    iconAsString = typeof el === 'string' ? el : el.outerHTML;\n\n    if (icons[iconAsString]) {\n      return icons[iconAsString];\n    }\n  }\n\n  let elToConvert: Element | null | string = el;\n\n  if (typeof elToConvert === 'string') {\n    const div = document.createElement('div');\n    div.innerHTML = elToConvert;\n    elToConvert = div.firstElementChild;\n  }\n\n  if (elToConvert === null) {\n    return h('span');\n  }\n\n  const attributes = Array.from(elToConvert.attributes);\n  const children = Array.from(elToConvert.children);\n  const attrs: VNodeProps & Data = {};\n\n  attributes\n    .filter((attribute: Attr) => !attribute.name.startsWith('on'))\n    .forEach((attribute: Attr) => {\n      attrs[attribute.name] = attribute.value;\n    });\n\n  const component = h(elToConvert.tagName, attrs, children.map((child) => svgToVueComponent(child, deep + 1)));\n\n  if (deep === 0 && iconAsString !== null) {\n    icons[iconAsString] = component;\n  }\n\n  return component;\n};\n"
  },
  {
    "path": "tailwind.config.js",
    "content": "module.exports = {\n  content: [\n    './src/development/**/*.{html,js,vue,ts}',\n    './node_modules/@variantjs/core/src/config/**/*.ts'\n  ],\n  plugins: [\n    require('@tailwindcss/forms'),\n  ],\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"esnext\",\n    \"module\": \"esnext\",\n    \"declaration\": true,\n    \"outDir\": \"./dist\",\n    \"moduleResolution\": \"node\",\n    \"strict\": true,\n    \"jsx\": \"preserve\",\n    \"sourceMap\": true,\n    \"resolveJsonModule\": true,\n    \"esModuleInterop\": true,\n    \"lib\": [\"esnext\", \"dom\"],\n    \"types\": [\"vite/client\", \"jest\"],\n  },\n  \"include\": [\"src/**/*.ts\", \"src/**/*.d.ts\", \"src/**/*.tsx\", \"src/**/*.vue\"],\n  \"exclude\": [\"node_modules\"]\n}\n"
  },
  {
    "path": "vite.config.ts",
    "content": "import path from 'path'\nimport { defineConfig } from 'vite'\nimport vue from '@vitejs/plugin-vue'\nimport typescript from '@rollup/plugin-typescript'\n\nexport default defineConfig({\n  plugins: [vue()],\n  build: {\n    minify: false,\n    sourcemap: true,\n    lib: {\n      entry: path.resolve(__dirname, 'src/index.ts'),\n      name: 'VariantJS',\n      fileName: (format) => `index.${format}.js`\n    },\n    rollupOptions: {\n      plugins: [\n        typescript({\n          \"exclude\": [\"node_modules\", 'src/__tests/**/*']\n        }),\n      ],\n      external: ['vue', '@popperjs/core', '@variantjs/core'],\n      output: {\n        globals: {\n          vue: 'Vue'\n        },\n      }\n    }\n  }\n})\n"
  },
  {
    "path": "vite.demo.config.ts",
    "content": "import { defineConfig } from 'vite'\nimport vue from '@vitejs/plugin-vue'\n\n// https://vitejs.dev/config/\nexport default defineConfig({\n  plugins: [vue()],\n})\n"
  }
]