import { computePosition } from '@floating-ui/dom' import clsx from 'clsx' import { computed, defineComponent, ref, h, Fragment, onMounted, onUnmounted, watch, } from 'vue' import type { CodeBlockProps } from './code-block' import { Icon } from '../../../__internal__/components/icon' import { keepAlive } from '../../../__internal__/keep-alive' keepAlive(h, Fragment) type LanguagePickerProps = Pick< CodeBlockProps, 'language' | 'config' | 'setLanguage' | 'getAllLanguages' | 'getReadOnly' > export const LanguagePicker = defineComponent({ props: { language: { type: Object, required: true, }, getReadOnly: { type: Function, required: true, }, config: { type: Object, required: true, }, getAllLanguages: { type: Function, required: true, }, setLanguage: { type: Function, required: true, }, }, setup({ language, config, setLanguage, getAllLanguages, getReadOnly }) { const triggerRef = ref() const showPicker = ref(false) const searchRef = ref() const pickerRef = ref() const filter = ref('') watch([showPicker, triggerRef, pickerRef], () => { filter.value = '' const picker = triggerRef.value const languageList = pickerRef.value if (!picker || !languageList) return computePosition(picker, languageList, { placement: 'bottom-start', }) .then(({ x, y }) => { Object.assign(languageList.style, { left: `${x}px`, top: `${y}px`, }) }) .catch(console.error) }) const onTogglePicker = (e: Event) => { e.preventDefault() e.stopPropagation() if (getReadOnly()) return const next = !showPicker.value showPicker.value = next if (next) { setTimeout(() => searchRef.value?.focus(), 0) } } const changeFilter = (e: Event) => { const target = e.target as HTMLInputElement filter.value = target.value } const onSearchKeydown = (e: Event) => { if ((e as KeyboardEvent).key === 'Escape') filter.value = '' } const languages = computed(() => { if (!showPicker.value) return [] const all = getAllLanguages() ?? [] const selected = all.find( (languageInfo) => languageInfo.name.toLowerCase() === language.value.toLowerCase() ) const filtered = all.filter((languageInfo) => { const currentValue = filter.value.toLowerCase() return ( (languageInfo.name.toLowerCase().includes(currentValue) || languageInfo.alias.some((alias) => alias.toLowerCase().includes(currentValue) )) && languageInfo !== selected ) }) if (filtered.length === 0) return [] if (!selected) return filtered return [selected, ...filtered] }) const clickHandler = (e: MouseEvent) => { const target = e.target as HTMLElement if (triggerRef.value && triggerRef.value.contains(target)) return const picker = pickerRef.value const trigger = triggerRef.value if (!trigger || !picker) return if (trigger.dataset.expanded !== 'true') return if (!picker.contains(target)) showPicker.value = false } onMounted(() => { window.addEventListener('click', clickHandler) }) onUnmounted(() => { window.removeEventListener('click', clickHandler) }) return () => { return ( <>
{showPicker.value ? (
    { if (e.key === 'Enter') { const active = document.activeElement if ( active instanceof HTMLElement && active.dataset.language ) setLanguage(active.dataset.language) } }} > {!languages.value.length ? (
  • {config.noResultText}
  • ) : ( languages.value.map((languageInfo) => (
  • { setLanguage(languageInfo.name) showPicker.value = false }} > {config.renderLanguage( languageInfo.name, languageInfo.name.toLowerCase() === language.value.toLowerCase() )}
  • )) )}
) : null}
) } }, })