Skip to content

Commit

Permalink
Show full height drop in modals, without user needs to scroll inside …
Browse files Browse the repository at this point in the history
…the modal (#11182)

* Add position fixed prop to ocSelect
  • Loading branch information
AlexAndBear authored Jul 16, 2024
1 parent 10f3f47 commit cb58290
Show file tree
Hide file tree
Showing 10 changed files with 110 additions and 40 deletions.
132 changes: 99 additions & 33 deletions packages/design-system/src/components/OcSelect/OcSelect.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
:clearable="clearable"
:multiple="multiple"
class="oc-select"
:class="{ 'oc-select-position-fixed': positionFixed }"
style="background: transparent"
:dropdown-should-open="selectDropdownShouldOpen"
:map-keydown="selectMapKeydown"
Expand All @@ -30,7 +31,9 @@
<template v-for="(index, name) in $slots" #[name]="data">
<slot v-if="name !== 'search'" :name="name" v-bind="data" />
</template>
<template #no-options><div v-text="$gettext('No options available.')" /></template>
<template #no-options>
<div v-text="$gettext('No options available.')" />
</template>
<template #spinner="{ loading: loadingSpinner }">
<oc-spinner v-if="loadingSpinner" />
</template>
Expand Down Expand Up @@ -97,7 +100,11 @@ import {
ref,
unref,
VNodeRef,
PropType
PropType,
nextTick,
onBeforeUnmount,
watch,
computed
} from 'vue'
import { useGettext } from 'vue3-gettext'
import 'vue-select/dist/vue-select.css'
Expand Down Expand Up @@ -280,6 +287,15 @@ export default defineComponent({
readOnly: {
type: Boolean,
default: false
},
/**
* Sets the dropdown menu to position: fixed.
* Use in modals, so the dropdown will be able to overflow.
* Positioning will be computed automatically
*/
positionFixed: {
type: Boolean,
default: false
}
},
emits: ['search:input', 'update:modelValue'],
Expand Down Expand Up @@ -354,6 +370,48 @@ export default defineComponent({
setDropdownEnabled(true)
}
const setDropdownPosition = () => {
const dropdownMenu = unref(select).$refs.dropdownMenu
if (!dropdownMenu) {
return
}
const toggleClientRect = unref(select).$refs.toggle.getBoundingClientRect()
const dropdownMenuBottomOffset = 25
const dropdownMenuMaxHeight = Math.min(
window.innerHeight - toggleClientRect.bottom - dropdownMenuBottomOffset,
window.innerHeight
)
dropdownMenu.style.maxHeight = `${dropdownMenuMaxHeight}px`
dropdownMenu.style.width = `${toggleClientRect.width}px`
dropdownMenu.style.top = `${toggleClientRect.top + toggleClientRect.height + 1}px`
dropdownMenu.style.left = `${toggleClientRect.left}px`
}
const dropdownOpen = computed(() => {
return unref(select)?.dropdownOpen
})
watch(dropdownOpen, async () => {
if (props.positionFixed && unref(dropdownOpen)) {
await nextTick()
setDropdownPosition()
}
})
onMounted(() => {
if (props.positionFixed) {
window.addEventListener('resize', setDropdownPosition)
}
})
onBeforeUnmount(() => {
if (props.positionFixed) {
window.removeEventListener('resize', setDropdownPosition)
}
})
return {
select,
userInput,
Expand Down Expand Up @@ -423,6 +481,13 @@ export default defineComponent({
padding: 1px 0;
color: var(--oc-color-input-text-default);
&-position-fixed {
.vs__dropdown-menu {
position: fixed;
overflow-y: auto;
}
}
.vs {
&__search {
color: var(--oc-color-input-text-default);
Expand Down Expand Up @@ -469,6 +534,7 @@ export default defineComponent({
&__deselect {
fill: var(--oc-color-input-text-default);
}
&__deselect {
margin: 0 var(--oc-space-small);
}
Expand Down Expand Up @@ -572,6 +638,7 @@ export default defineComponent({
&.vs--open .vs__selected {
opacity: 0.8 !important;
}
.vs__selected-options > *:not(input) {
background-color: transparent !important;
}
Expand All @@ -584,7 +651,7 @@ For detailed documentation (props, slots, events, etc.), please visit https://vu
```js
<template>
<div class="oc-docs-width-medium">
<oc-select label="Custom label" v-model="selected" :options="['Bannana', 'Orange', 'Pear']" />
<oc-select label="Custom label" v-model="selected" :options="['Bannana', 'Orange', 'Pear']"/>
</div>
</template>
<script>
Expand All @@ -603,7 +670,7 @@ prevent clearing the selected value by hitting `delete`.
```js
<template>
<div class="oc-docs-width-medium">
<oc-select v-model="selected" :options="['Apple', 'Bannana', 'Orange', 'Pear']" :clearable="false" />
<oc-select v-model="selected" :options="['Apple', 'Bannana', 'Orange', 'Pear']" :clearable="false"/>
</div>
</template>
<script>
Expand All @@ -619,7 +686,7 @@ prevent clearing the selected value by hitting `delete`.
```js
<template>
<div class="oc-docs-width-medium">
<oc-select v-model="selected" :multiple="true" :options="options" />
<oc-select v-model="selected" :multiple="true" :options="options"/>
</div>
</template>
<script>
Expand All @@ -644,7 +711,7 @@ To prevent user from filtering options by typing a serach query into the `oc-sel
```js
<template>
<div class="oc-docs-width-medium">
<oc-select v-model="selected" :options="['Apple', 'Bannana', 'Orange', 'Pear']" :searchable="false" />
<oc-select v-model="selected" :options="['Apple', 'Bannana', 'Orange', 'Pear']" :searchable="false"/>
</div>
</template>
<script>
Expand All @@ -657,7 +724,8 @@ To prevent user from filtering options by typing a serach query into the `oc-sel
```

### Use objects as options
If we want to select from a list of option objects, we can use `option-label` to select the key of the object to use as label.
If we want to select from a list of option objects, we can use `option-label` to select the key of the object to use as
label.

```js
<template>
Expand All @@ -672,33 +740,31 @@ If we want to select from a list of option objects, we can use `option-label` to
</div>
</template>
<script>
const options = [
{
title: 'Apple',
desc: 'An apple is an edible fruit produced by an apple tree (Malus domestica)'
},
{
title: 'Bannana',
desc: 'Bannana is a genus of goblin spiders (family Oonopidae) native to Xishuangbanna prefecture, Yunnan Province, China, where it lives in the leaf-litter of tropical rainforest'
},
{
title: 'Orange',
desc: 'The orange is the fruit of various citrus species in the family Rutaceae'
},
]
const options = [
{
title: 'Apple',
desc: 'An apple is an edible fruit produced by an apple tree (Malus domestica)'
},
{
title: 'Bannana',
desc: 'Bannana is a genus of goblin spiders (family Oonopidae) native to Xishuangbanna prefecture, Yunnan Province, China, where it lives in the leaf-litter of tropical rainforest'
},
{
title: 'Orange',
desc: 'The orange is the fruit of various citrus species in the family Rutaceae'
},
]

export default {
data: () => ({
selected: options[1],
options
})
}
export default {
data: () => ({
selected: options[1],
options
})
}
</script>
```




### Using slots to display complex options
Sometimes we need to display more complex options. This can include e.g. an option with a title and a description. To
still display all those values exactly as we want to, we need to use scoped slots called `option` and `selected-option`.
Expand All @@ -716,15 +782,15 @@ It is important to specify the `option-label` prop on the `oc-select` to make fi
>
<template v-slot:option="{ title, desc }">
<span class="option">
<strong v-text="title" />
<strong v-text="title"/>
</span>
<span class="option" v-text="desc" />
<span class="option" v-text="desc"/>
</template>
<template #no-options>
Your search query hasn't returned any results.
</template>
<template #selected-option="{ title, desc }">
<strong class="oc-mr-s" v-text="title" /> <small v-text="desc.slice(0, 20) + '...'" />
<strong class="oc-mr-s" v-text="title"/> <small v-text="desc.slice(0, 20) + '...'"/>
</template>
</oc-select>
<p>
Expand Down Expand Up @@ -764,6 +830,6 @@ It is important to specify the `option-label` prop on the `oc-select` to make fi

## Loading spinner
```js
<oc-select :options="['Apple', 'Bannana', 'Orange', 'Pear']" :multiple="true" :loading="true" />
<oc-select :options="['Apple', 'Bannana', 'Orange', 'Pear']" :multiple="true" :loading="true"/>
```
</docs>
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,6 @@ import { $gettext } from '@ownclouders/web-pkg/src/router/utils'
export default defineComponent({
name: 'SpacesList',
methods: { $gettext },
components: { ContextMenuQuickAction, Pagination },
setup() {
const router = useRouter()
Expand Down Expand Up @@ -539,7 +538,8 @@ export default defineComponent({
selectSpaces,
unselectAllSpaces
}
}
},
methods: { $gettext }
})
</script>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<group-select
:selected-groups="selectedOptions"
:group-options="groups"
:position-fixed="true"
@selected-option-change="changeSelectedGroupOption"
/>
</template>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
:warning-message="
currentUserSelected ? $gettext('Your own login status will remain unchanged.') : ''
"
:position-fixed="true"
@update:model-value="changeSelectedOption"
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<group-select
:selected-groups="selectedOptions"
:group-options="groups"
:position-fixed="true"
@selected-option-change="changeSelectedGroupOption"
/>
</template>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ exports[`EditPanel > renders all available inputs 1`] = `
<oc-text-input-stub id="email-input" type="email" modelvalue="[email protected]" clearbuttonenabled="false" clearbuttonaccessiblelabel="" disabled="false" label="Email" errormessage="" fixmessageline="true" readonly="false" passwordpolicy="[object Object]" class="oc-mb-s"></oc-text-input-stub>
<oc-text-input-stub id="password-input" type="password" modelvalue="" clearbuttonenabled="false" clearbuttonaccessiblelabel="" disabled="false" label="Password" fixmessageline="true" readonly="false" passwordpolicy="[object Object]" class="oc-mb-s" placeholder="●●●●●●●●"></oc-text-input-stub>
<div class="oc-mb-s">
<oc-select-stub id="role-input" filter="[Function]" disabled="false" label="Role" optionlabel="displayName" getoptionlabel="[Function]" searchable="true" clearable="false" loading="false" fixmessageline="false" multiple="false" readonly="false" options="[object Object]"></oc-select-stub>
<oc-select-stub id="role-input" filter="[Function]" disabled="false" label="Role" optionlabel="displayName" getoptionlabel="[Function]" searchable="true" clearable="false" loading="false" fixmessageline="false" multiple="false" readonly="false" positionfixed="false" options="[object Object]"></oc-select-stub>
<div class="oc-text-input-message"></div>
</div>
<div class="oc-mb-s">
<oc-select-stub id="login-input" filter="[Function]" disabled="false" label="Login" optionlabel="label" getoptionlabel="[Function]" searchable="true" clearable="false" loading="false" fixmessageline="false" multiple="false" readonly="false" model-value="[object Object]" options="[object Object],[object Object]"></oc-select-stub>
<oc-select-stub id="login-input" filter="[Function]" disabled="false" label="Login" optionlabel="label" getoptionlabel="[Function]" searchable="true" clearable="false" loading="false" fixmessageline="false" multiple="false" readonly="false" positionfixed="false" model-value="[object Object]" options="[object Object],[object Object]"></oc-select-stub>
<div class="oc-text-input-message"></div>
</div>
<quota-select-stub totalquota="0" maxquota="0" id="quota-select-form" disabled="false" class="oc-mb-s" label="Personal quota" fix-message-line="true" description-message="" read-only="false"></quota-select-stub>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

exports[`GroupSelect > renders the select input 1`] = `
"<div id="user-group-select-form">
<oc-select-stub id="oc-select-1" filter="[Function]" disabled="false" label="Groups" optionlabel="displayName" getoptionlabel="[Function]" searchable="true" clearable="false" loading="false" fixmessageline="true" multiple="true" readonly="false" model-value="[object Object]" class="oc-mb-s" options="undefined"></oc-select-stub>
<oc-select-stub id="oc-select-1" filter="[Function]" disabled="false" label="Groups" optionlabel="displayName" getoptionlabel="[Function]" searchable="true" clearable="false" loading="false" fixmessageline="true" multiple="true" readonly="false" positionfixed="false" model-value="[object Object]" class="oc-mb-s" options="undefined"></oc-select-stub>
</div>"
`;
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

exports[`LoginModal > renders the input including two options 1`] = `
"<div>
<oc-select-stub id="oc-select-1" filter="[Function]" disabled="false" label="Login" optionlabel="label" getoptionlabel="[Function]" searchable="true" clearable="false" loading="false" warningmessage="" fixmessageline="false" multiple="false" readonly="false" options="[object Object],[object Object]" placeholder="Select..."></oc-select-stub>
<oc-select-stub id="oc-select-1" filter="[Function]" disabled="false" label="Login" optionlabel="label" getoptionlabel="[Function]" searchable="true" clearable="false" loading="false" warningmessage="" fixmessageline="false" multiple="false" readonly="false" positionfixed="true" options="[object Object],[object Object]" placeholder="Select..."></oc-select-stub>
</div>"
`;
1 change: 1 addition & 0 deletions packages/web-pkg/src/components/Spaces/QuotaModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
:label="$gettext('Quota')"
:total-quota="selectedOption"
:max-quota="maxQuota"
:position-fixed="true"
@selected-option-change="changeSelectedQuotaOption"
/>
<div v-if="warningMessage" class="oc-mt-s">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ exports[`account page > public link context > should render a limited view 1`] =
<div data-v-f2ac0579="" class="account-page-info-language oc-mb oc-width-1-2@m oc-width-1-1@s">
<dt data-v-f2ac0579="" class="oc-text-normal oc-text-muted">Language</dt>
<dd data-v-f2ac0579="" data-testid="language" class="oc-width-1-3@l oc-width-1-2@m oc-width-1-1@s">
<oc-select-stub data-v-f2ac0579="" id="oc-select-1" filter="[Function]" disabled="false" optionlabel="label" getoptionlabel="[Function]" searchable="true" clearable="false" loading="false" fixmessageline="false" multiple="false" readonly="false" placeholder="Please choose..." options="[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]" model-value="[object Object]"></oc-select-stub>
<oc-select-stub data-v-f2ac0579="" id="oc-select-1" filter="[Function]" disabled="false" optionlabel="label" getoptionlabel="[Function]" searchable="true" clearable="false" loading="false" fixmessageline="false" multiple="false" readonly="false" positionfixed="false" placeholder="Please choose..." options="[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]" model-value="[object Object]"></oc-select-stub>
<div data-v-f2ac0579="" class="oc-mt-s"><a data-v-f2ac0579="" href="https://explore.transifex.com/owncloud-org/owncloud-web/" target="_blank" class="oc-flex oc-flex-middle">
<oc-icon-stub data-v-f2ac0579="" name="service" class="oc-mr-xs"></oc-icon-stub> <span data-v-f2ac0579="">Help translate</span>
</a></div>
Expand Down

0 comments on commit cb58290

Please sign in to comment.