Skip to content

Commit

Permalink
feat: add anchor prop to select-menu
Browse files Browse the repository at this point in the history
Signed-off-by: Saulo Vallory <[email protected]>
  • Loading branch information
svallory committed Dec 28, 2024
1 parent bc2163f commit ce45a87
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 20 deletions.
6 changes: 2 additions & 4 deletions packages/ui/src/lib/components/select-menu/select-item.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,13 @@
outline: none;
transition-property: background-color;
transition-duration: 30ms;
text-transform: lowercase;
text-wrap: nowrap;
white-space: nowrap;
}
.label {
overflow-x: hidden;
white-space: nowrap;
text-overflow: ellipsis;
pointer-events: none;
text-transform: lowercase;
}
.highlight,
Expand Down
86 changes: 70 additions & 16 deletions packages/ui/src/lib/components/select-menu/select-menu.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@
export let value: SelectMenuItem | null | undefined = null;
export let showGroupLabels: boolean = false;
export let className = '';
export let anchor:
| 'top'
| 'right'
| 'bottom'
| 'left'
| 'top-left'
| 'top-right'
| 'bottom-left'
| 'bottom-right' = 'bottom-left';
const dispatch = createEventDispatcher();
const groups = checkGroups();
Expand Down Expand Up @@ -101,8 +110,11 @@
return;
}
// Handle button click
if ((event.target as HTMLElement).contains(menuButton) || event.target === menuButton) {
// Handle button click - check if click is on button or any of its children
const clickedElement = event.target as HTMLElement;
const isButtonClick = menuButton.contains(clickedElement) || clickedElement === menuButton;
if (isButtonClick) {
if (menuList.classList.contains('hidden')) {
menuList.classList.remove('hidden');
menuButton.classList.add('selected');
Expand Down Expand Up @@ -147,12 +159,53 @@
// New helper function for menu positioning
function positionMenu(targetItem: HTMLElement) {
const buttonRect = menuButton.getBoundingClientRect();
// Set width to fit content but not smaller than button
menuList.style.width = 'max-content';
menuList.style.minWidth = `${buttonRect.width}px`;
const menuRect = menuList.getBoundingClientRect();
const spaceAbove = buttonRect.top;
const spaceBelow = window.innerHeight - buttonRect.bottom;
// Always position menu above the button
menuList.style.bottom = '34px'; // Fixed position above button
menuList.style.top = 'auto';
// Reset styles
menuList.style.left = '';
menuList.style.right = '';
menuList.style.top = '';
menuList.style.bottom = '';
menuList.style.maxHeight = '472px';
menuList.style.transform = '';
// Handle vertical positioning
if (anchor.includes('top') || anchor === 'top') {
menuList.style.top = `${buttonRect.top - menuRect.height - 4}px`;
menuList.style.maxHeight = `${Math.min(472, spaceAbove - 10)}px`;
} else if (anchor.includes('bottom') || anchor === 'bottom') {
menuList.style.top = `${buttonRect.bottom + 4}px`;
menuList.style.maxHeight = `${Math.min(472, spaceBelow - 10)}px`;
}
// Handle horizontal positioning
if (anchor.includes('right') || anchor === 'right') {
menuList.style.left = `${buttonRect.right - menuRect.width}px`;
} else if (anchor.includes('left') || anchor === 'left') {
menuList.style.left = `${buttonRect.left}px`;
}
// Handle single direction anchors
if (anchor === 'top' || anchor === 'bottom') {
// Center horizontally
menuList.style.left = `${buttonRect.left + (buttonRect.width - menuRect.width) / 2}px`;
} else if (anchor === 'left' || anchor === 'right') {
// Center vertically
menuList.style.top = `${buttonRect.top + buttonRect.height / 2}px`;
menuList.style.transform = 'translateY(-50%)';
if (anchor === 'left') {
menuList.style.left = `${buttonRect.right + 4}px`;
} else {
menuList.style.left = `${buttonRect.left - menuRect.width - 4}px`;
}
}
// Scroll to selected item
if (targetItem) {
Expand Down Expand Up @@ -208,13 +261,13 @@
{/if}

{#if value}
<Text class="label">{value.label}</Text>
<Text class="selected-value">{value.label}</Text>
{:else}
<Text emphasis="tertiary" class="placeholder">{placeholder}</Text>
{/if}

{#if !disabled}
<span class="caret">
<div class="caret">
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
fill-rule="evenodd"
Expand All @@ -223,7 +276,7 @@
fill="black"
/>
</svg>
</span>
</div>
{/if}
</button>

Expand Down Expand Up @@ -298,7 +351,7 @@
button:focus .placeholder {
color: var(--figma-color-text);
}
button:disabled .label {
button:disabled .selected-value {
color: var(--figma-color-text-secondary);
}
button:disabled:hover {
Expand All @@ -315,14 +368,15 @@
pointer-events: none;
}
.label,
.selected-value,
.placeholder {
display: inline-block;
font-size: var(--text-body-medium-font-size);
font-weight: var(--font-weight-default);
letter-spacing: var(--font-letter-spacing-neg-xsmall);
line-height: var(--line-height);
color: var(--figma-color-text);
margin-right: 6px;
margin-right: var(--space-2);
margin-top: -3px;
white-space: nowrap;
overflow-x: hidden;
Expand Down Expand Up @@ -350,10 +404,10 @@
}
.menu {
position: absolute;
left: 0;
bottom: 34px; // Forces menu to open upwards
width: 100%;
position: fixed;
width: max-content;
min-width: auto;
max-width: max(400px, 90vw);
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
Expand All @@ -367,7 +421,7 @@
letter-spacing: var(--letter-spacing-default);
color: var(--color-text-menu);
box-shadow: var(--elevation-400);
z-index: 1000;
z-index: 2147483647;
text-transform: lowercase;
}
.menu::-webkit-scrollbar {
Expand Down

0 comments on commit ce45a87

Please sign in to comment.