Skip to content

feat: add dropdownOptionWrap prop with 3 strategies #1530

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

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
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
18 changes: 18 additions & 0 deletions docs/.vuepress/components/OptionWrapStrategy.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<template>
<v-select
:dropdown-option-wrap="wrap"
:options="[
'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'Mauris molestie, orci non dapibus interdum, sapien velit gravida ex, vel rutrum purus augue tempor ligula.',
'Cras et felis in massa maximus tempor. Praesent malesuada enim eget sollicitudin luctus. Praesent ullamcorper euismod nisi, vel volutpat diam volutpat eu.',
'Nunc suscipit laoreet nunc. Donec rhoncus blandit nibh et auctor. Mauris euismod erat non gravida egestas.',
]"
/>
</template>

<script>
export default {
name: 'OptionWrapStrategy',
props: ['wrap'],
}
</script>
21 changes: 21 additions & 0 deletions docs/api/props.md
Original file line number Diff line number Diff line change
@@ -198,6 +198,27 @@ disabled: {
},
```

## dropdownOptionWrap <Badge text="v3.17.0+ />

Determines how to handle option labels that are
wider than the dropdown itself.

Accepts:
- `nowrap`: **default** don't wrap the option, introduce horizontal scrollbars
- `wrap`: wrap the option onto the next line, no scrollbarrs
- `truncate`: truncate text with ..., no scrollbars


```js
dropdownOptionWrap: {
type: String,
default: 'nowrap',
validator(wrap) {
return ['nowrap', 'wrap', 'truncate'].includes(wrap)
},
},
```

## dropdownShouldOpen <Badge text="v3.12.0+" />

Determines whether the dropdown should open. Used
69 changes: 53 additions & 16 deletions docs/guide/css.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
Vue Select offers many APIs for customizing the look and feel from the component. You can use
[scoped slots](../api/slots.md), [custom child components](components.md), or modify the built in
SCSS variables.
Vue Select offers many APIs for customizing the look and feel from the component. You can use
[scoped slots](../api/slots.md), [custom child components](components.md), or modify the built in
SCSS variables.

::: tip
Support for CSS variables (custom properties) is currently on the road map for those
that are not using sass in their projects.
:::
::: tip Support for CSS variables (custom properties) is currently on the road map for those that
are not using sass in their projects.
:::

## SCSS Variables

Variables are leveraged in as much of the component styles as possible. If you really want to dig
into the SCSS, the files are located in `src/scss`. The variables listed below can be found at
[`src/scss/global/_variables`](https://github.com/sagalbot/vue-select/blob/master/src/scss/global/_variables.scss).
[`src/scss/global/_variables`](https://github.com/sagalbot/vue-select/blob/master/src/scss/global/_variables.scss)
.

All variables are implemented with `!default` in order to make them easier to override in your
application.
@@ -23,12 +23,12 @@ application.
Vue Select takes the approach of using selectors with a single level of specificity, while using
classes that are very specific to Vue Select to avoid collisions with your app.

All classes within Vue Select use the `vs__` prefix, and selectors are generally a single classname
All classes within Vue Select use the `vs__` prefix, and selectors are generally a single classname
– unless there is a state being applied to the component.

In order to override a default property in your app, you should add one level of specificity.
The easiest way to do this, is to add `.v-select` before the `vs__*` selector if you want to adjust
all instances of Vue Select, or add your own classname if you just want to affect one.
In order to override a default property in your app, you should add one level of specificity. The
easiest way to do this, is to add `.v-select` before the `vs__*` selector if you want to adjust all
instances of Vue Select, or add your own classname if you just want to affect one.

<CssSpecificity />

@@ -38,21 +38,58 @@ all instances of Vue Select, or add your own classname if you just want to affec

By default, the dropdown transitions with a `.15s` cubic-bezier opacity fade in/out. The component
uses the [VueJS transition system](https://vuejs.org/v2/guide/transitions.html). By default, the
transition name is `vs__fade`. There's a couple ways to override or change this transition.
transition name is `vs__fade`. There's a couple ways to override or change this transition.

1. Use the `transition` prop. Applying this prop will change the name of the animation classes and
negate the default CSS. If you want to remove it entirely, you can set it to an empty string.
negate the default CSS. If you want to remove it entirely, you can set it to an empty string.

```html

<v-select transition="" />
```

2. You can also override the default CSS for the `vs__fade` transition. Again, if you
wanted to eliminate the transition entirely:
2. You can also override the default CSS for the `vs__fade` transition. Again, if you wanted to
eliminate the transition entirely:

```css
.vs__fade-enter-active,
.vs__fade-leave-active {
transition: none;
}
```

## Option Wrapping Strategy

When options in the dropdown are wider than the dropdown itself, there are three strategies
available. The strategy can be set with the `dropdownOptionWrap` prop. This prop accepts one of
three strings:

### `wrap`

Break options that are wider than the dropdown onto the next line. No horizontal scrollbar.

```vue
<v-select dropdown-option-wrap="wrap" />
```

<OptionWrapStrategy wrap="wrap" />

### `truncate`

Truncate options that are wider than the dropdown using an ellipsis `...`. No horizontal scrollbar.

```vue
<v-select dropdown-option-wrap="truncate" />
```

<OptionWrapStrategy wrap="truncate" />

### `nowrap`

Don't wrap or truncate options wider than the dropdown. Introduces horizontal scrollbar.

```vue
<v-select dropdown-option-wrap="nowrap" />
```

<OptionWrapStrategy wrap="nowrap" />
35 changes: 27 additions & 8 deletions src/components/Select.vue
Original file line number Diff line number Diff line change
@@ -102,13 +102,16 @@
:key="getOptionKey(option)"
role="option"
class="vs__dropdown-option"
:class="{
'vs__dropdown-option--deselect':
isOptionDeselectable(option) && index === typeAheadPointer,
'vs__dropdown-option--selected': isOptionSelected(option),
'vs__dropdown-option--highlight': index === typeAheadPointer,
'vs__dropdown-option--disabled': !selectable(option),
}"
:class="[
`vs__dropdown-option--${dropdownOptionWrap}`,
{
'vs__dropdown-option--deselect':
isOptionDeselectable(option) && index === typeAheadPointer,
'vs__dropdown-option--selected': isOptionSelected(option),
'vs__dropdown-option--highlight': index === typeAheadPointer,
'vs__dropdown-option--disabled': !selectable(option),
},
]"
:aria-selected="index === typeAheadPointer ? true : null"
@mouseover="selectable(option) ? (typeAheadPointer = index) : null"
@click.prevent.stop="selectable(option) ? select(option) : null"
@@ -555,6 +558,21 @@ export default {
default: 'auto',
},

/**
* Determines how to handle option labels that are
* wider than the dropdown itself. Accepts:
* - nowrap: don't wrap the option, introduce horizontal scrollbars
* - wrap: wrap the option onto the next line
* - truncate: truncate text with ...
*/
dropdownOptionWrap: {
type: String,
default: 'nowrap',
validator(wrap) {
return ['nowrap', 'wrap', 'truncate'].includes(wrap)
},
},

/**
* When true, hitting the 'tab' key will select the current select value
* @type {Boolean}
@@ -593,7 +611,6 @@ export default {
* for the search input. Can be used to implement
* custom behaviour for key presses.
*/

mapKeydown: {
type: Function,
/**
@@ -818,6 +835,8 @@ export default {
'vs--open': this.dropdownOpen,
'vs--single': !this.multiple,
'vs--multiple': this.multiple,
'vs--empty': this.selectedValue.length === 0,
'vs--not-empty': this.selectedValue.length !== 0,
'vs--searching': this.searching && !this.noDrop,
'vs--searchable': this.searchable && !this.noDrop,
'vs--unsearchable': !this.searchable,
42 changes: 22 additions & 20 deletions src/scss/modules/_dropdown-menu.scss
Original file line number Diff line number Diff line change
@@ -12,27 +12,29 @@ $min-width: $vs-dropdown-min-width;
$max-height: $vs-dropdown-max-height;

.vs__dropdown-menu {
display: block;
box-sizing: border-box;
position: absolute;
top: calc(100% - #{$border-width}); // -{#$border-width} here ensures the left and right borders of the dropdown appear flush with the toggle.
left: 0;
z-index: $z-index;
padding: 5px 0;
margin: 0;
width: 100%;
max-height: $max-height;
min-width: $min-width;
overflow-y: auto;
box-shadow: $box-shadow;
border: $border-width $border-style $border-color;
border-top-style: none;
border-radius: 0 0 $border-radius $border-radius;
text-align: left;
list-style: none;
background: $bg-color;
display: grid;
box-sizing: border-box;
position: absolute;
top: calc(
100% - #{$border-width}
); // -{#$border-width} here ensures the left and right borders of the dropdown appear flush with the toggle.
left: 0;
z-index: $z-index;
padding: 5px 0;
margin: 0;
width: 100%;
max-height: $max-height;
min-width: $min-width;
overflow-y: auto;
box-shadow: $box-shadow;
border: $border-width $border-style $border-color;
border-top-style: none;
border-radius: 0 0 $border-radius $border-radius;
text-align: left;
list-style: none;
background: $bg-color;
}

.vs__no-options {
text-align: center;
text-align: center;
}
43 changes: 29 additions & 14 deletions src/scss/modules/_dropdown-option.scss
Original file line number Diff line number Diff line change
@@ -1,26 +1,41 @@
/* List Items */
.vs__dropdown-option {
line-height: 1.42857143; /* Normalize line height */
display: block;
padding: 3px 20px;
clear: both;
color: #333; /* Overrides most CSS frameworks */
white-space: nowrap;
cursor: pointer;
line-height: 1.42857143; /* Normalize line height */
display: block;
padding: 3px 20px;
clear: both;
color: #333; /* Overrides most CSS frameworks */
cursor: pointer;
}

.vs__dropdown-option--wrap {
white-space: normal;
line-break: loose;
overflow-wrap: anywhere;
}

.vs__dropdown-option--nowrap {
white-space: nowrap;
}

.vs__dropdown-option--truncate {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

.vs__dropdown-option--highlight {
background: $vs-state-active-bg;
color: $vs-state-active-color;
background: $vs-state-active-bg;
color: $vs-state-active-color;
}

.vs__dropdown-option--deselect {
background: $vs-state-deselect-bg;
color: $vs-state-deselect-color;
background: $vs-state-deselect-bg;
color: $vs-state-deselect-color;
}

.vs__dropdown-option--disabled {
background: inherit;
color: $vs-state-disabled-color;
cursor: inherit;
background: inherit;
color: $vs-state-disabled-color;
cursor: inherit;
}
Loading
Oops, something went wrong.