refactor: Button components (#6929)

* feat: refactor button components

* fix: qa

* fix: storybook

* a11y: pass

* fix: build

* fix: rename default ->md

* fix: lint

* docs: buttons.md

* refactor part 1

* refactor part 2

* fix: undo refactor for fresh restart

* refactor

* Revert "refactor"

This reverts commit 96d65902d7.

* refactor: part 1

* fix: qa

* fix: qa

* fix: qa

* fix: qa

* fix: qa

* fix: qa

* fix: qa

* fix: qa

* fix: remove text-contrast

* fix: qa

* fix: v-tooltip

* fix: lint

* fix: split broken

* fix: passkey qa

* fix: qa

* fix: qa

* fix: prepr

* fix: splitbutton

* improve button group seam

---------

Signed-off-by: Calum H. <calum@modrinth.com>
Co-authored-by: Prospector <6166773+Prospector@users.noreply.github.com>
This commit is contained in:
Calum H.
2026-08-04 13:54:04 -07:00
committed by GitHub
co-authored by Prospector
parent 6cfe999cb3
commit bb2193b6f5
398 changed files with 13688 additions and 13133 deletions
+30 -15
View File
@@ -49,19 +49,19 @@
</div>
<!-- Standard mode: button trigger -->
<span
<ButtonFrame
v-else
ref="triggerRef"
role="button"
tabindex="0"
class="relative flex min-h-5 w-full items-center justify-between overflow-hidden rounded-xl bg-surface-4 px-4 py-2 text-left transition-all duration-200 text-button-text gap-2.5"
as="button"
native-type="button"
:type="triggerType"
:size="triggerSize"
:interaction="triggerInteraction"
:disabled="disabled"
:class="[
'min-w-full w-full !justify-between overflow-hidden text-left',
props.triggerClass,
{
'z-[9999]': isOpen,
'cursor-not-allowed opacity-50': disabled,
'cursor-pointer hover:brightness-[115%] active:brightness-[115%]': !disabled,
},
{ 'z-[9999]': isOpen },
]"
:aria-expanded="isOpen"
:aria-haspopup="listbox ? 'listbox' : 'menu'"
@@ -78,7 +78,7 @@
/>
<span
v-if="selectedOption"
class="min-w-0 truncate text-primary font-semibold leading-tight"
class="min-w-0 truncate font-semibold leading-tight text-inherit"
>
<slot name="selected" :label="selectedTriggerText">{{ selectedTriggerText }}</slot>
</span>
@@ -94,7 +94,7 @@
:class="isOpen ? (openDirection === 'down' ? 'rotate-90' : '-rotate-90') : '-rotate-90'"
/>
</div>
</span>
</ButtonFrame>
<Teleport to="#teleports">
<Transition
@@ -217,6 +217,13 @@ import {
watch,
} from 'vue'
import ButtonFrame from './buttons/ButtonFrame.vue'
import type {
ButtonElementHandle,
ButtonInteraction,
ButtonSize,
ButtonType,
} from './buttons/types'
import StyledInput from './StyledInput.vue'
export interface ComboboxOption<T> {
@@ -281,6 +288,10 @@ const props = withDefaults(
displayValue?: string
searchValue?: string
triggerClass?: string
/** Shared button frame style for non-searchable combobox triggers. */
triggerType?: ButtonType
triggerSize?: ButtonSize
triggerInteraction?: ButtonInteraction
dropdownClass?: string
/** Additional selectors to ignore when detecting outside clicks */
outsideClickIgnore?: string[]
@@ -322,6 +333,9 @@ const props = withDefaults(
selectSearchTextOnFocus: false,
showSearchIcon: false,
searchType: 'text',
triggerType: 'base',
triggerSize: 'md',
triggerInteraction: 'surface',
outsideClickIgnore: () => [],
},
)
@@ -343,7 +357,7 @@ const searchQuery = ref('')
const userHasTyped = ref(false)
const focusedIndex = ref(-1)
const containerRef = ref<HTMLElement>()
const triggerRef = ref<HTMLElement>()
const triggerRef = ref<ButtonElementHandle>()
const searchTriggerRef = ref<InstanceType<typeof StyledInput>>()
const dropdownRef = ref<HTMLElement>()
const optionsScrollbarRef = ref<HTMLElement>()
@@ -357,10 +371,11 @@ const effectiveTriggerEl = computed(() => {
if (props.searchable && searchTriggerRef.value) {
return (searchTriggerRef.value as unknown as { $el: HTMLElement }).$el as HTMLElement
}
return triggerRef.value
return triggerRef.value?.element ?? undefined
})
const outsideClickIgnoreTargets = computed(() => [
triggerRef,
effectiveTriggerEl,
containerRef,
...props.outsideClickIgnore,
])
@@ -642,7 +657,7 @@ function closeDropdown() {
if (!props.searchable) {
nextTick(() => {
triggerRef.value?.focus()
effectiveTriggerEl.value?.focus()
})
}
}