|
| 1 | +<script setup lang="ts"> |
| 2 | +import { BuiltinIcon, HstButton } from '@histoire/controls/vue' |
| 3 | +import { useHistoireContext } from '@histoire/vue/internal' |
| 4 | +import { computed, ref, shallowRef } from 'vue' |
| 5 | +import BasePopover from '../base/popover/BasePopover.vue' |
| 6 | +
|
| 7 | +const props = defineProps<{ |
| 8 | + /** Offline Carbon glyph name shown before label. */ |
| 9 | + icon: string |
| 10 | + /** Short visible action label. */ |
| 11 | + label: string |
| 12 | + /** Disables main action and options trigger. */ |
| 13 | + disabled?: boolean |
| 14 | + /** Accessible name of options trigger and its menu. */ |
| 15 | + menuLabel?: string |
| 16 | + /** Options menu width in pixels. */ |
| 17 | + menuWidth?: number |
| 18 | +}>() |
| 19 | +const emit = defineEmits<{ |
| 20 | + /** Main action activated. */ |
| 21 | + click: [event: MouseEvent] |
| 22 | +}>() |
| 23 | +defineSlots<{ |
| 24 | + /** Optional secondary options; renders split chevron trigger when present. */ |
| 25 | + menu?: (props: { close: () => void }) => any |
| 26 | +}>() |
| 27 | +
|
| 28 | +const context = useHistoireContext() |
| 29 | +const open = ref(false) |
| 30 | +const chevron = shallowRef<InstanceType<typeof HstButton> | null>(null) |
| 31 | +const anchor = computed(() => (chevron.value?.element as HTMLElement | undefined) ?? null) |
| 32 | +const resolvedMenuLabel = computed(() => props.menuLabel ?? `${props.label} options`) |
| 33 | +
|
| 34 | +/** Dismiss options menu after an item runs. */ |
| 35 | +function close(): void { |
| 36 | + open.value = false |
| 37 | +} |
| 38 | +</script> |
| 39 | + |
| 40 | +<template> |
| 41 | + <div class="workbench-panel-action" :class="{ split: $slots.menu }"> |
| 42 | + <HstButton color="primary" type="button" class="workbench-panel-action-main" :disabled="disabled" @click="emit('click', $event)"> |
| 43 | + <BuiltinIcon :icon="icon" :size="16" />{{ label }} |
| 44 | + </HstButton> |
| 45 | + <template v-if="$slots.menu"> |
| 46 | + <HstButton ref="chevron" color="primary" type="button" class="workbench-panel-action-options" icon-only :aria-label="resolvedMenuLabel" aria-haspopup="menu" :aria-expanded="open" :disabled="disabled" @click="open = !open"> |
| 47 | + <BuiltinIcon icon="chevron-down" :size="16" /> |
| 48 | + </HstButton> |
| 49 | + <BasePopover v-if="open" v-model:open="open" :anchor="anchor" :label="resolvedMenuLabel" role="menu" :width="menuWidth ?? 160" :overlay-target="context.overlay.value ?? context.root.value"> |
| 50 | + <slot name="menu" :close="close" /> |
| 51 | + </BasePopover> |
| 52 | + </template> |
| 53 | + </div> |
| 54 | +</template> |
| 55 | + |
| 56 | +<style scoped> |
| 57 | +/* Pane header CTA: height follows shared control height so every tab's primary action matches across density modes. */ |
| 58 | +.workbench-panel-action { display: inline-flex; flex: none; gap: 1px; --histoire-icon-button-size: var(--histoire-control-height, 34px); } |
| 59 | +.workbench-panel-action-main { box-sizing: border-box; height: var(--histoire-control-height, 34px); padding-block: 0; padding-inline: 10px; font-weight: 750; white-space: nowrap; } |
| 60 | +.split .workbench-panel-action-main { border-start-end-radius: 0; border-end-end-radius: 0; } |
| 61 | +.workbench-panel-action-options { border-start-start-radius: 0; border-end-start-radius: 0; } |
| 62 | +</style> |
0 commit comments