Skip to main content
Glama
ContentSelector.vue3.04 kB
<script setup lang="ts"> import { ref, computed, useSlots, onMounted, onBeforeUnmount } from 'vue'; type Props = { onClickOutside?: () => void; pressDuration?: number; isSelecting?: boolean; }; const DEFAULT_PRESS_DETECT_DURATION = 250; const props = defineProps<Props>(); const emit = defineEmits(['click', 'press', 'hover', 'unhover']); const containerRef = ref<HTMLElement | null>(null); const isHovered = ref(false); const isSelectingState = ref(props.isSelecting ?? false); const pressTimerRef = ref<ReturnType<typeof setTimeout> | null>(null); const isSelecting = computed(() => props.isSelecting ?? isSelectingState.value); const isStringSlot = computed(() => { // If there's only one default slot child and it's a string const slot = useSlots().default?.(); return slot?.length === 1 && typeof slot[0].children === 'string'; }); const handleOnLongPress = () => { isSelectingState.value = true; emit('press'); }; const startPressTimer = () => { pressTimerRef.value = setTimeout(() => { handleOnLongPress(); }, props.pressDuration ?? DEFAULT_PRESS_DETECT_DURATION); }; const clearPressTimer = () => { if (pressTimerRef.value) { clearTimeout(pressTimerRef.value); pressTimerRef.value = null; } }; const handleMouseDown = () => { clearPressTimer(); startPressTimer(); }; const handleMouseUp = () => { if (isHovered.value) { isHovered.value = false; emit('unhover'); } clearPressTimer(); }; const handleMouseLeave = () => { if (isHovered.value) { isHovered.value = false; emit('unhover'); } clearPressTimer(); }; const handleClickOutside = (event: MouseEvent) => { if ( containerRef.value && !containerRef.value.contains(event.target as Node) ) { isSelectingState.value = false; props.onClickOutside?.(); } }; const handleClick = (e: MouseEvent) => { if (isSelecting.value) { e.preventDefault(); e.stopPropagation(); } }; const handleBlur = () => { isSelectingState.value = false; }; onMounted(() => { document.addEventListener('mousedown', handleClickOutside); }); onBeforeUnmount(() => { document.removeEventListener('mousedown', handleClickOutside); clearPressTimer(); }); </script> <template> <span ref="containerRef" role="button" tabindex="0" @click="handleClick" @mousedown="handleMouseDown" @mouseup="handleMouseUp" @mouseleave="handleMouseLeave" @touchstart="handleMouseDown" @touchend="handleMouseUp" @touchcancel="handleMouseLeave" @blur="handleBlur" @mouseenter=" () => { isHovered = true; emit('hover'); } " :style="{ display: isStringSlot ? 'inline' : 'inline-block', cursor: 'pointer', userSelect: 'none', borderRadius: '0.375rem', outlineWidth: '2px', outlineOffset: '4px', outlineStyle: 'solid', outlineColor: isSelecting || isHovered ? 'inherit' : 'transparent', transition: 'all 100ms 50ms ease-in-out', }" > <slot /> </span> </template>

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/aymericzip/intlayer'

If you have feedback or need assistance with the MCP directory API, please join our Discord server