diff --git a/dev/Dev.vue b/dev/Dev.vue index ab8e964..5096a5a 100644 --- a/dev/Dev.vue +++ b/dev/Dev.vue @@ -1,43 +1,99 @@ - - diff --git a/docs/assets/static/data.ts b/docs/assets/static/data.ts new file mode 100644 index 0000000..e69de29 diff --git a/docs/content/guide/opening.md b/docs/content/guide/opening.md index a8af952..19a08fc 100644 --- a/docs/content/guide/opening.md +++ b/docs/content/guide/opening.md @@ -3,12 +3,9 @@ By default, the dropdown will open anytime the underlying search input has focus. The dropdown will open when clicked, or when it has received focus when tabbing through inputs. -## Customizing Dropdown Behaviour +## Customizing Dropdown Behaviour -The `dropdownShouldOpen` prop allows for full customization of the open/close behaviour. The prop -accepts a `function` that should return a `boolean` value. The returned boolean value will be used -to determine if the dropdown should be `open`/`true` or `false`/`closed`. The function receives the -instance of the component as the only argument. +The `open` prop can control showing and hiding the dropdown menu from a parent component. If this prop is set, the component will always use the value of `props.open` to handle showing and hiding the dropdown. Vue Select will emit the `update:open` when the prop value should change, so you can use `` to have control over the `open` state while preserving default behaviour. #### Example: Open the dropdown when search text is present --- diff --git a/index.html b/index.html index 6222ae8..e31fb28 100644 --- a/index.html +++ b/index.html @@ -1,9 +1,10 @@ - - - Vue Select Dev + + + Vue Select Dev +
diff --git a/package.json b/package.json index a92d5a8..d8b125c 100644 --- a/package.json +++ b/package.json @@ -1,104 +1,104 @@ { - "name": "vue-select", - "version": "4.0.0-beta.6", - "description": "Everything you wish the HTML element could do, wrapped up into a lightweight, extensible Vue component.", + "author": "Jeff Sagal ", + "homepage": "https://vue-select.org", + "directories": { + "doc": "docs", + "test": "tests" + }, + "files": [ + "dist" + ], + "main": "./dist/vue-select.umd.js", + "module": "./dist/vue-select.es.js", + "exports": { + ".": { + "import": "./dist/vue-select.es.js", + "require": "./dist/vue-select.umd.js" }, - "files": [ - "dist" - ], - "main": "./dist/vue-select.umd.js", - "module": "./dist/vue-select.es.js", - "exports": { - ".": { - "import": "./dist/vue-select.es.js", - "require": "./dist/vue-select.umd.js" - }, - "./dist/vue-select.css": { - "import": "./dist/vue-select.css", - "require": "./dist/vue-select.css", - "style": "./dist/vue-select.css" - } - }, - "private": false, - "license": "MIT", - "prepare": "npm run build", - "scripts": { - "dev:docs": "cd docs && yarn dev", - "build:docs": "cd docs && yarn generate", - "semantic-release": "semantic-release", - "commit": "git-cz", - "dev": "vite", - "build": "vue-tsc --noEmit && vite build", - "preview": "vite preview --port 5050", - "test": "vitest --environment jsdom", - "coverage": "vitest --run --coverage --environment jsdom --silent", - "typecheck": "vue-tsc --noEmit -p tsconfig.vitest.json --composite false", - "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore" - }, - "repository": { - "type": "git", - "url": "https://github.com/sagalbot/vue-select.git" - }, - "peerDependencies": { - "vue": "3.x" - }, - "devDependencies": { - "@rushstack/eslint-patch": "^1.8.0", - "@semantic-release/git": "^10.0.1", - "@semantic-release/github": "^10.0.2", - "@types/jsdom": "^21.1.6", - "@types/node": "^20.11.30", - "@vitejs/plugin-vue": "^5.0.4", - "@vitest/coverage-c8": "^0.33.0", - "@vue/eslint-config-prettier": "^9.0.0", - "@vue/eslint-config-typescript": "^13.0.0", - "@vue/test-utils": "^2.4.5", - "@vue/tsconfig": "^0.5.1", - "autoprefixer": "^10.4.19", - "bundlewatch": "^0.3.3", - "commitizen": "^4.3.0", - "coveralls": "^3.1.1", - "cross-env": "^7.0.3", - "cz-conventional-changelog": "3.3.0", - "eslint": "^8.57.0", - "eslint-plugin-vue": "^9.23.0", - "jsdom": "^24.0.0", - "postcss-nested": "^6.0.1", - "prettier": "^3.2.5", - "semantic-release": "^23.0.5", - "typescript": "^5.4.3", - "vite": "^5.2.2", - "vitest": "^1.4.0", - "vue": "^3.4.21", - "vue-tsc": "^2.0.7" - }, - "config": { - "commitizen": { - "path": "./node_modules/cz-conventional-changelog" - } - }, - "bundlewatch": { - "files": [ - { - "path": "./dist/vue-select.es.js", - "compression": "gzip", - "maxSize": "8 KB" - }, - { - "path": "./dist/vue-select.umd.js", - "compression": "gzip", - "maxSize": "7 KB" - }, - { - "path": "./dist/vue-select.css", - "compression": "gzip", - "maxSize": "2 KB" - } - ] + "./dist/vue-select.css": { + "import": "./dist/vue-select.css", + "require": "./dist/vue-select.css", + "style": "./dist/vue-select.css" } + }, + "private": false, + "license": "MIT", + "prepare": "npm run build", + "scripts": { + "dev:docs": "cd docs && yarn dev", + "build:docs": "cd docs && yarn generate", + "semantic-release": "semantic-release", + "commit": "git-cz", + "dev": "vite", + "build": "vue-tsc --noEmit && vite build", + "preview": "vite preview --port 5050", + "test": "vitest --environment jsdom", + "coverage": "vitest --run --coverage --environment jsdom --silent", + "typecheck": "vue-tsc --noEmit -p tsconfig.vitest.json --composite false", + "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore" + }, + "repository": { + "type": "git", + "url": "https://github.com/sagalbot/vue-select.git" + }, + "peerDependencies": { + "vue": "3.x" + }, + "devDependencies": { + "@rushstack/eslint-patch": "^1.8.0", + "@semantic-release/git": "^10.0.1", + "@semantic-release/github": "^10.0.2", + "@types/jsdom": "^21.1.6", + "@types/node": "^20.11.30", + "@vitejs/plugin-vue": "^5.0.4", + "@vitest/coverage-v8": "^1.4.0", + "@vue/eslint-config-prettier": "^9.0.0", + "@vue/eslint-config-typescript": "^13.0.0", + "@vue/test-utils": "^2.4.5", + "@vue/tsconfig": "^0.5.1", + "autoprefixer": "^10.4.19", + "bundlewatch": "^0.3.3", + "commitizen": "^4.3.0", + "coveralls": "^3.1.1", + "cross-env": "^7.0.3", + "cz-conventional-changelog": "3.3.0", + "eslint": "^8.57.0", + "eslint-plugin-vue": "^9.23.0", + "jsdom": "^24.0.0", + "postcss-nested": "^6.0.1", + "prettier": "^3.2.5", + "semantic-release": "^23.0.5", + "typescript": "^5.4.3", + "vite": "^5.2.3", + "vitest": "^1.4.0", + "vue": "^3.4.21", + "vue-tsc": "^2.0.7" + }, + "config": { + "commitizen": { + "path": "./node_modules/cz-conventional-changelog" + } + }, + "bundlewatch": { + "files": [ + { + "path": "./dist/vue-select.es.js", + "compression": "gzip", + "maxSize": "8 KB" + }, + { + "path": "./dist/vue-select.umd.js", + "compression": "gzip", + "maxSize": "7 KB" + }, + { + "path": "./dist/vue-select.css", + "compression": "gzip", + "maxSize": "2 KB" + } + ] + } } diff --git a/src/components/ComboBox/ComboBox.vue b/src/components/ComboBox/ComboBox.vue new file mode 100644 index 0000000..0f4d34c --- /dev/null +++ b/src/components/ComboBox/ComboBox.vue @@ -0,0 +1,72 @@ + + + diff --git a/src/components/ComboBox/ComboBoxButton.vue b/src/components/ComboBox/ComboBoxButton.vue new file mode 100644 index 0000000..277d184 --- /dev/null +++ b/src/components/ComboBox/ComboBoxButton.vue @@ -0,0 +1,28 @@ + + + diff --git a/src/components/ComboBox/ComboBoxInput.vue b/src/components/ComboBox/ComboBoxInput.vue new file mode 100644 index 0000000..a0e71b9 --- /dev/null +++ b/src/components/ComboBox/ComboBoxInput.vue @@ -0,0 +1,13 @@ + + + diff --git a/src/components/ComboBox/ComboBoxMenu.vue b/src/components/ComboBox/ComboBoxMenu.vue new file mode 100644 index 0000000..160dfea --- /dev/null +++ b/src/components/ComboBox/ComboBoxMenu.vue @@ -0,0 +1,21 @@ + + + diff --git a/src/components/ComboBox/ComboBoxOption.vue b/src/components/ComboBox/ComboBoxOption.vue new file mode 100644 index 0000000..efe1c12 --- /dev/null +++ b/src/components/ComboBox/ComboBoxOption.vue @@ -0,0 +1,26 @@ + + + diff --git a/src/components/ComboBox/StyledComboBox.vue b/src/components/ComboBox/StyledComboBox.vue new file mode 100644 index 0000000..4670c79 --- /dev/null +++ b/src/components/ComboBox/StyledComboBox.vue @@ -0,0 +1,50 @@ + + + diff --git a/src/hooks/useClickAway.ts b/src/hooks/useClickAway.ts new file mode 100644 index 0000000..cbce154 --- /dev/null +++ b/src/hooks/useClickAway.ts @@ -0,0 +1,21 @@ +export function useClickAway(callback: () => void): { + addClickAwayListener: (el: HTMLElement | undefined) => void + removeClickAwayListener: (el: HTMLElement | undefined) => void +} { + function clickedOutside(el: HTMLElement | undefined, event: MouseEvent) { + if (el && !(el == event.target || el?.contains(event.target))) { + callback() + } + } + + return { + addClickAwayListener: (el) => + document.addEventListener('click', (event: MouseEvent) => + clickedOutside(el, event) + ), + removeClickAwayListener: (el) => + document.removeEventListener('click', (event: MouseEvent) => + clickedOutside(el, event) + ), + } +} diff --git a/src/hooks/useComboBox.ts b/src/hooks/useComboBox.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/hooks/useModelValue.ts b/src/hooks/useModelValue.ts new file mode 100644 index 0000000..4cb9d01 --- /dev/null +++ b/src/hooks/useModelValue.ts @@ -0,0 +1,5 @@ +export function useModelValue( + props: Readonly, + key: string, + emit: (name: string, ...args: any[]) => void +) {} diff --git a/src/keys.ts b/src/keys.ts new file mode 100644 index 0000000..5ca5bed --- /dev/null +++ b/src/keys.ts @@ -0,0 +1,8 @@ +import type { InjectionKey } from 'vue' +import type { ResolvedListBoxProps } from '@/types' + +export const ListBoxKey: InjectionKey = Symbol( + 'ListBoxInjectionKey', +) + +export const ListBoxOptionInjectionKey = Symbol() as InjectionKey diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..3324f2b --- /dev/null +++ b/src/types.ts @@ -0,0 +1,16 @@ +import { ComputedRef, PropType } from 'vue' + +export type VueSelectValue = PropType +export type VueSelectOption = PropType + +export interface ListBoxProps { + modelValue: VueSelectValue + open?: boolean | undefined +} +export interface ResolvedListBoxProps extends Omit { + open: boolean + inputText: string + toggleOpen: () => boolean + setInputText: (text: string) => void + setModelValue: (value: unknown) => void +} diff --git a/tsconfig.vite-config.json b/tsconfig.vite-config.json index d20d872..6910fce 100644 --- a/tsconfig.vite-config.json +++ b/tsconfig.vite-config.json @@ -1,5 +1,5 @@ { - "extends": "@vue/tsconfig/tsconfig.node.json", + "extends": "@vue/tsconfig/tsconfig.dom.json", "include": ["vite.config.*"], "compilerOptions": { "composite": true,