Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix overflowing selected of options #1756

Open
wants to merge 45 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
5e1fad0
Add aria-multiselectable
Pytal Dec 14, 2022
5baaa76
Fix dropdown not opening after closing
Pytal Jan 20, 2023
246df60
Merge pull request #1 from nextcloud-deps/enh/a11y-aria-multiselectable
Pytal Jan 27, 2023
61f4211
Merge pull request #2 from nextcloud-deps/fix/open-dropdown-on-enter
Pytal Jan 27, 2023
ac01c0f
Handle keyboard focus
Pytal Jan 13, 2023
73e0b04
Darken default dropdown active bg color
Pytal Jan 13, 2023
bc141b7
Add CSS variable and class styles
Pytal Jan 13, 2023
15be9de
Merge pull request #3 from nextcloud-deps/enh/a11y-keyboard-focus-border
Pytal Jan 27, 2023
6b6582b
v3.21.0
Pytal Jan 27, 2023
16dbb47
Merge pull request #4 from nextcloud-deps/v3.21.0
Pytal Jan 27, 2023
bf4309f
Add @nextcloud namespace to package name
Pytal Jan 31, 2023
2e6f141
Merge pull request #5 from nextcloud-deps/nextcloud-namespace
Pytal Jan 31, 2023
7bdd579
v3.21.1
Pytal Jan 31, 2023
d7d042a
Merge pull request #6 from nextcloud-deps/v3.21.1
Pytal Jan 31, 2023
12466c9
Fix keyboard focus not returning to input after clear
Pytal Feb 1, 2023
9ef870b
Merge pull request #7 from nextcloud-deps/fix/a11y-clear-kb-focus
Pytal Feb 1, 2023
9e36609
v3.21.2
Pytal Feb 1, 2023
4eed18c
Merge pull request #8 from nextcloud-deps/v3.21.2
Pytal Feb 1, 2023
aab477b
Fix return focus after keyboard deselect
Pytal Feb 7, 2023
0cae604
Merge pull request #9 from nextcloud-deps/fix/a11y-kb-focus-deselect
Pytal Feb 7, 2023
89a6f98
Use browser agnostic handling for keyboard deselect focus
Pytal Feb 7, 2023
2d5bfe4
Merge pull request #10 from nextcloud-deps/fix/a11y-agnostic-focus
Pytal Feb 8, 2023
cd294db
v3.21.3
Pytal Feb 8, 2023
d3c78a5
Merge pull request #11 from nextcloud-deps/v3.21.3
Pytal Feb 8, 2023
a7ccfe1
Limit number of dropdown options
Pytal Feb 9, 2023
e2b333b
Merge pull request #12 from nextcloud-deps/enh/limit-options
Pytal Feb 9, 2023
f91b453
v3.22.0
Pytal Feb 10, 2023
d61274d
Merge pull request #13 from nextcloud-deps/v3.22.0
Pytal Feb 10, 2023
9bfce3f
Fix calculated dropdown list width
Pytal Feb 11, 2023
750521e
Merge pull request #14 from nextcloud-deps/fix/append-body-calc-width
Pytal Feb 11, 2023
72f78a6
Update package metadata
Pytal Feb 14, 2023
0f9d47f
Update README
Pytal Feb 14, 2023
8a70129
Merge pull request #15 from nextcloud-deps/nextcloud-package
Pytal Feb 14, 2023
e2581dc
v3.22.1
Pytal Feb 14, 2023
1839cbe
Merge pull request #16 from nextcloud-deps/v3.22.1
Pytal Feb 14, 2023
eb20f15
v3.22.2
Pytal Feb 14, 2023
28f12fb
Merge pull request #17 from nextcloud-deps/v3.22.2
Pytal Feb 14, 2023
71dd57d
fix: Overflowing selected options
susnux Feb 15, 2023
9294fdc
Merge pull request #18 from susnux/master
Pytal Feb 28, 2023
7730cb5
fix(docs): Fix CI shield on readme
susnux May 31, 2023
f7d3452
Merge pull request #19 from susnux/fix/readme
Pytal May 31, 2023
eb042bb
Allow disabling focus reset
Pytal Jun 22, 2023
6ae2091
Merge pull request #20 from nextcloud-deps/enh/reset-focus
Pytal Jun 23, 2023
93bdaab
v3.23.0
Pytal Jun 23, 2023
6ee86a9
Merge pull request #21 from nextcloud-deps/v3.23.0
Pytal Jun 23, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# vue-select ![Current Release](https://img.shields.io/github/release/sagalbot/vue-select.svg?style=flat-square) ![Release Date](https://img.shields.io/github/release-date/sagalbot/vue-select?style=flat-square) ![Bundle Size](https://flat.badgen.net/bundlephobia/min/vue-select) ![Monthly Downloads](https://img.shields.io/npm/dm/vue-select.svg?style=flat-square) [![Coverage Status](https://coveralls.io/repos/github/sagalbot/vue-select/badge.svg?branch=master)](https://coveralls.io/github/sagalbot/vue-select?branch=master) ![MIT License](https://img.shields.io/github/license/sagalbot/vue-select.svg?style=flat-square)
# @nextcloud/vue-select
![Current Release](https://img.shields.io/github/release/nextcloud-deps/vue-select?style=flat-square) ![Release Date](https://img.shields.io/github/release-date/nextcloud-deps/vue-select?style=flat-square) ![Bundle Size](https://flat.badgen.net/bundlephobia/min/@nextcloud/vue-select) ![Monthly Downloads](https://img.shields.io/npm/dm/@nextcloud/vue-select?style=flat-square) ![MIT License](https://img.shields.io/github/license/sagalbot/vue-select.svg?style=flat-square)

> **Everything you wish the HTML `<select>` element could do, wrapped up into a lightweight, zero
> dependency, extensible Vue component.**
Expand Down
11 changes: 7 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
{
"name": "vue-select",
"version": "3.20.2",
"name": "@nextcloud/vue-select",
"version": "3.23.0",
"description": "Everything you wish the HTML <select> element could do, wrapped up into a lightweight, extensible Vue component.",
"author": "Jeff Sagal <[email protected]>",
"homepage": "https://vue-select.org",
"contributors": [
"Christopher Ng <[email protected]>"
],
"homepage": "https://github.com/nextcloud-deps/vue-select",
"directories": {
"doc": "docs",
"test": "tests"
Expand All @@ -26,7 +29,7 @@
},
"repository": {
"type": "git",
"url": "https://github.com/sagalbot/vue-select.git"
"url": "https://github.com/nextcloud-deps/vue-select.git"
},
"peerDependencies": {
"vue": "2.x"
Expand Down
124 changes: 118 additions & 6 deletions src/components/Select.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
>
<div ref="selectedOptions" class="vs__selected-options">
<slot
v-for="option in selectedValue"
v-for="(option, index) in selectedValue"
name="selected-option-container"
:option="normalizeOptionForSlot(option)"
:deselect="deselect"
Expand All @@ -39,7 +39,8 @@
class="vs__deselect"
:title="`Deselect ${getOptionLabel(option)}`"
:aria-label="`Deselect ${getOptionLabel(option)}`"
@click="deselect(option)"
@mousedown.stop="deselect(option)"
@keydown.enter="keyboardDeselect(option, index)"
>
<component :is="childComponents.Deselect" />
</button>
Expand Down Expand Up @@ -91,6 +92,7 @@
v-append-to-body
class="vs__dropdown-menu"
role="listbox"
:aria-multiselectable="multiple"
tabindex="-1"
@mousedown.prevent="onMousedown"
@mouseup="onMouseUp"
Expand All @@ -107,10 +109,11 @@
isOptionDeselectable(option) && index === typeAheadPointer,
'vs__dropdown-option--selected': isOptionSelected(option),
'vs__dropdown-option--highlight': index === typeAheadPointer,
'vs__dropdown-option--kb-focus': hasKeyboardFocusBorder(index),
'vs__dropdown-option--disabled': !selectable(option),
}"
:aria-selected="index === typeAheadPointer ? true : null"
@mouseover="selectable(option) ? (typeAheadPointer = index) : null"
:aria-selected="optionAriaSelected(option)"
@mousemove="onMouseMove(option, index)"
@click.prevent.stop="selectable(option) ? select(option) : null"
>
<slot name="option" v-bind="normalizeOptionForSlot(option)">
Expand Down Expand Up @@ -190,6 +193,15 @@ export default {
},
},

/**
* Sets the maximum number of options to display in the dropdown list
* @type {Number}
*/
limit: {
type: Number,
default: null,
},

/**
* Disable the entire component.
* @type {Boolean}
Expand Down Expand Up @@ -497,6 +509,16 @@ export default {
},
},

/**
* If false, the focused dropdown option will not be reset when filtered
* options change.
* @type {Boolean}
*/
resetFocusOnOptionsChange: {
type: Boolean,
default: true,
},

/**
* When false, updating the options will not reset the selected value. Accepts
* a `boolean` or `function` that returns a `boolean`. If defined as a function,
Expand Down Expand Up @@ -660,6 +682,15 @@ export default {
},
},

/**
* Display a visible border around dropdown options
* which have keyboard focus.
*/
keyboardFocusBorder: {
type: Boolean,
default: false,
},

/**
* A unique identifier used to generate IDs in HTML.
* Must be unique for every instance of the component.
Expand All @@ -675,6 +706,7 @@ export default {
search: '',
open: false,
isComposing: false,
isKeyboardNavigation: false,
pushedTags: [],
// eslint-disable-next-line vue/no-reserved-keys
_value: [], // Internal value managed by Vue Select if no `value` prop is passed
Expand Down Expand Up @@ -868,10 +900,17 @@ export default {
* @return {array}
*/
filteredOptions() {
const limitOptions = (options) => {
if (this.limit !== null) {
return options.slice(0, this.limit)
}
return options
}

const optionList = [].concat(this.optionList)

if (!this.filterable && !this.taggable) {
return optionList
return limitOptions(optionList)
}

let options = this.search.length
Expand All @@ -883,7 +922,7 @@ export default {
options.unshift(createdOption)
}
}
return options
return limitOptions(options)
},

/**
Expand Down Expand Up @@ -1029,12 +1068,38 @@ export default {
this.$emit('option:deselected', option)
},

/**
* De-select a given option on keyboard input.
* @param {Object|String} option
* @param {Number} index
* @return {void}
*/
keyboardDeselect(option, index) {
this.deselect(option)
/**
* The index of the next deselect is not yet at the same index as the
* removed deselect element because Vue updates asynchronously
*
* $nextTick cannot be used as the tests will fail even after using
* $nextTick in the tests as well
*/
const nextDeselect = this.$refs.deselectButtons?.[index + 1]
const prevDeselect = this.$refs.deselectButtons?.[index - 1]
const deselectToFocus = nextDeselect ?? prevDeselect
if (deselectToFocus) {
deselectToFocus.focus()
} else {
this.searchEl.focus()
}
},

/**
* Clears the currently selected value(s)
* @return {void}
*/
clearSelection() {
this.updateValue(this.multiple ? [] : null)
this.searchEl.focus()
},

/**
Expand Down Expand Up @@ -1134,6 +1199,19 @@ export default {
return this.isOptionSelected(option) && this.deselectFromDropdown
},

/**
* Check if the option at the given index should display a
* keyboard focus border.
* @param {Number} index
* @return {Boolean}
*/
hasKeyboardFocusBorder(index) {
if (this.keyboardFocusBorder && this.isKeyboardNavigation) {
return index === this.typeAheadPointer
}
return false
},

/**
* Determine if two option objects are matching.
*
Expand Down Expand Up @@ -1221,6 +1299,20 @@ export default {
)
},

/**
* Determine the `aria-selected` value
* of an option
*
* @param {Object|String} option
* @return {null|string}
*/
optionAriaSelected(option) {
if (!this.selectable(option)) {
return null
}
return String(this.isOptionSelected(option))
},

/**
* Ensures that options are always
* passed as objects to scoped slots.
Expand Down Expand Up @@ -1309,6 +1401,20 @@ export default {
this.mousedown = false
},

/**
* Event-Handler for option mousemove
* @param {Object|String} option
* @param {Number} index
* @return {void}
*/
onMouseMove(option, index) {
this.isKeyboardNavigation = false
if (!this.selectable(option)) {
return
}
this.typeAheadPointer = index
},

/**
* Search <input> KeyBoardEvent handler.
* @param {KeyboardEvent} e
Expand All @@ -1317,6 +1423,10 @@ export default {
onSearchKeyDown(e) {
const preventAndSelect = (e) => {
e.preventDefault()
if (!this.open) {
this.open = true
return
}
return !this.isComposing && this.typeAheadSelect()
}

Expand All @@ -1330,6 +1440,7 @@ export default {
// up.prevent
38: (e) => {
e.preventDefault()
this.isKeyboardNavigation = true
if (!this.open) {
this.open = true
return
Expand All @@ -1339,6 +1450,7 @@ export default {
// down.prevent
40: (e) => {
e.preventDefault()
this.isKeyboardNavigation = true
if (!this.open) {
this.open = true
return
Expand Down
5 changes: 4 additions & 1 deletion src/css/global/variables.css
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,12 @@
--vs-dropdown-option-padding: 3px 20px;

/* Active State */
--vs-dropdown-option--active-bg: #5897fb;
--vs-dropdown-option--active-bg: #136cfb;
--vs-dropdown-option--active-color: #fff;

/* Keyboard Focus State */
--vs-dropdown-option--kb-focus-box-shadow: inset 0px 0px 0px 2px #949494;

/* Deselect State */
--vs-dropdown-option--deselect-bg: #fb5858;
--vs-dropdown-option--deselect-color: #fff;
Expand Down
4 changes: 4 additions & 0 deletions src/css/modules/dropdown-option.css
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
color: var(--vs-dropdown-option--active-color);
}

.vs__dropdown-option--kb-focus {
box-shadow: var(--vs-dropdown-option--kb-focus-box-shadow);
}

.vs__dropdown-option--deselect {
background: var(--vs-dropdown-option--deselect-bg);
color: var(--vs-dropdown-option--deselect-color);
Expand Down
1 change: 1 addition & 0 deletions src/css/modules/dropdown-toggle.css
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
flex-basis: 100%;
flex-grow: 1;
flex-wrap: wrap;
min-width: 0;
padding: 0 2px;
position: relative;
}
Expand Down
2 changes: 2 additions & 0 deletions src/css/modules/selected.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
color: var(--vs-selected-color);
line-height: var(--vs-line-height);
margin: 4px 2px 0px 2px;
min-width: 0;
padding: 0 0.25em;
z-index: 0;
}
Expand All @@ -34,6 +35,7 @@
}
&.vs--open .vs__selected,
&.vs--loading .vs__selected {
max-width: 100%;
position: absolute;
opacity: 0.4;
}
Expand Down
4 changes: 2 additions & 2 deletions src/directives/appendToBody.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
export default {
inserted(el, bindings, { context }) {
if (context.appendToBody) {
document.body.appendChild(el)

const {
height,
top,
Expand All @@ -16,8 +18,6 @@ export default {
left: scrollX + left + 'px',
top: scrollY + top + height + 'px',
})

document.body.appendChild(el)
}
},

Expand Down
3 changes: 3 additions & 0 deletions src/mixins/typeAheadPointer.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ export default {

watch: {
filteredOptions() {
if (!this.resetFocusOnOptionsChange) {
return
}
for (let i = 0; i < this.filteredOptions.length; i++) {
if (this.selectable(this.filteredOptions[i])) {
this.typeAheadPointer = i
Expand Down
Loading