Skip to content

Commit 96a9618

Browse files
authored
feat(UI): Dropdowns now automatically open either above or below (#706)
Depending on where there is more space. Fixes #692
1 parent c979293 commit 96a9618

File tree

3 files changed

+24
-24
lines changed

3 files changed

+24
-24
lines changed

skore-ui/src/components/DropdownButton.vue

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,25 @@
1-
<script lang="ts">
2-
export interface DropdownProps {
3-
label?: string;
4-
icon?: string;
5-
isPrimary?: boolean;
6-
align?: "left" | "right";
7-
isInline?: boolean;
8-
}
9-
</script>
10-
111
<script setup lang="ts">
12-
import { autoUpdate, useFloating } from "@floating-ui/vue";
2+
import { autoPlacement, autoUpdate, useFloating, type Placement } from "@floating-ui/vue";
133
import { computed, onBeforeUnmount, onMounted, ref } from "vue";
144
15-
import SimpleButton from "@/components/SimpleButton.vue";
5+
import SimpleButton, { type ButtonProps } from "@/components/SimpleButton.vue";
166
17-
const { label, icon, isPrimary = false, align = "left", isInline } = defineProps<DropdownProps>();
7+
interface DropdownProps extends ButtonProps {
8+
allowedPlacements?: Placement[];
9+
}
10+
11+
const props = withDefaults(defineProps<DropdownProps>(), {
12+
isPrimary: false,
13+
allowedPlacements: () => ["top-end", "bottom-end", "top-start", "bottom-start"],
14+
});
1815
1916
const isOpen = ref(false);
2017
const el = ref<HTMLDivElement>();
2118
const reference = ref<HTMLElement>();
2219
const floating = ref<HTMLDivElement>();
2320
const { floatingStyles } = useFloating(reference, floating, {
24-
placement: align === "right" ? "bottom-end" : "bottom-start",
2521
strategy: "fixed",
22+
middleware: [autoPlacement({ allowedPlacements: props.allowedPlacements as Placement[] })],
2623
whileElementsMounted: autoUpdate,
2724
});
2825
@@ -87,12 +84,12 @@ onBeforeUnmount(() => {
8784
</script>
8885

8986
<template>
90-
<div class="dropdown" ref="el" :class="{ 'align-right': align === 'right' }">
87+
<div class="dropdown" ref="el">
9188
<SimpleButton
92-
:is-primary="isPrimary"
93-
:label="label"
94-
:icon="icon"
95-
:is-inline="isInline"
89+
:is-primary="props.isPrimary"
90+
:label="props.label"
91+
:icon="props.icon"
92+
:is-inline="props.isInline"
9693
@click="isOpen = !isOpen"
9794
ref="reference"
9895
/>

skore-ui/src/components/DropdownButtonItem.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ const props = withDefaults(defineProps<DropdownItemProps>(), { iconPosition: "le
2929
<style scoped>
3030
.dropdown-item {
3131
display: inline-block;
32+
width: 100%;
3233
box-sizing: border-box;
3334
padding: var(--spacing-6);
3435
border: 0;

skore-ui/src/components/SimpleButton.vue

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
1-
<script setup lang="ts">
2-
import { generateRandomMultiple } from "@/services/utils";
3-
import { onBeforeMount, ref } from "vue";
4-
5-
interface ButtonProps {
1+
<script lang="ts">
2+
export interface ButtonProps {
63
label?: string;
74
icon?: string;
85
isPrimary?: boolean;
96
isInline?: boolean;
107
}
8+
</script>
9+
10+
<script setup lang="ts">
11+
import { generateRandomMultiple } from "@/services/utils";
12+
import { onBeforeMount, ref } from "vue";
1113
1214
const props = withDefaults(defineProps<ButtonProps>(), { isPrimary: false });
1315
const randomBackgroundOffsetX = ref(0);

0 commit comments

Comments
 (0)