UNPKG

reka-ui

Version:

Vue port for Radix UI Primitives.

1 lines 9.54 kB
{"version":3,"file":"SelectRoot.cjs","sources":["../../src/Select/SelectRoot.vue"],"sourcesContent":["<script lang=\"ts\">\nimport type { Ref } from 'vue'\nimport type { AcceptableValue, Direction, FormFieldProps } from '@/shared/types'\nimport { createContext, isNullish, useDirection, useFormControl } from '@/shared'\nimport { compare } from './utils'\nimport { useCollection } from '@/Collection'\n\nexport interface SelectRootProps<T = AcceptableValue> extends FormFieldProps {\n /** The controlled open state of the Select. Can be bind as `v-model:open`. */\n open?: boolean\n /** The open state of the select when it is initially rendered. Use when you do not need to control its open state. */\n defaultOpen?: boolean\n /** The value of the select when initially rendered. Use when you do not need to control the state of the Select */\n defaultValue?: T | Array<T>\n /** The controlled value of the Select. Can be bind as `v-model`. */\n modelValue?: T | Array<T>\n /** Use this to compare objects by a particular field, or pass your own comparison function for complete control over how objects are compared. */\n by?: string | ((a: T, b: T) => boolean)\n /** The reading direction of the combobox when applicable. <br> If omitted, inherits globally from `ConfigProvider` or assumes LTR (left-to-right) reading mode. */\n dir?: Direction\n /** Whether multiple options can be selected or not. */\n multiple?: boolean\n /** Native html input `autocomplete` attribute. */\n autocomplete?: string\n /** When `true`, prevents the user from interacting with Select */\n disabled?: boolean\n}\n\nexport type SelectRootEmits<T = AcceptableValue> = {\n /** Event handler called when the value changes. */\n 'update:modelValue': [value: T]\n /** Event handler called when the open state of the context menu changes. */\n 'update:open': [value: boolean]\n}\n\nexport interface SelectRootContext<T> {\n triggerElement: Ref<HTMLElement | undefined>\n onTriggerChange: (node: HTMLElement | undefined) => void\n valueElement: Ref<HTMLElement | undefined>\n onValueElementChange: (node: HTMLElement) => void\n contentId: string\n modelValue: Ref<T | Array<T> | undefined>\n onValueChange: (value: T) => void\n open: Ref<boolean>\n multiple: Ref<boolean>\n required?: Ref<boolean>\n by?: string | ((a: T, b: T) => boolean)\n onOpenChange: (open: boolean) => void\n dir: Ref<Direction>\n triggerPointerDownPosRef: Ref<{ x: number, y: number } | null>\n isEmptyModelValue: Ref<boolean>\n disabled?: Ref<boolean>\n\n optionsSet: Ref<Set<SelectOption>>\n onOptionAdd: (option: SelectOption) => void\n onOptionRemove: (option: SelectOption) => void\n}\n\nexport const [injectSelectRootContext, provideSelectRootContext]\n = createContext<SelectRootContext<AcceptableValue>>('SelectRoot')\n\ninterface SelectOption { value: any, disabled?: boolean, textContent: string }\n</script>\n\n<script setup lang=\"ts\" generic=\"T extends AcceptableValue = AcceptableValue\">\nimport { computed, ref, toRefs } from 'vue'\nimport BubbleSelect from './BubbleSelect.vue'\nimport { PopperRoot } from '@/Popper'\nimport { useVModel } from '@vueuse/core'\n\ndefineOptions({\n inheritAttrs: false,\n})\n\nconst props = withDefaults(defineProps<SelectRootProps>(), {\n modelValue: undefined,\n open: undefined,\n})\nconst emits = defineEmits<SelectRootEmits>()\n\ndefineSlots<{\n default: (props: {\n /** Current input values */\n modelValue: typeof modelValue.value\n /** Current open state */\n open: typeof open.value\n }) => any\n}>()\n\nconst { required, disabled, multiple, dir: propDir } = toRefs(props)\n\nconst modelValue = useVModel(props, 'modelValue', emits, {\n defaultValue: props.defaultValue ?? (multiple.value ? [] : undefined),\n passive: (props.modelValue === undefined) as false,\n deep: true,\n}) as Ref<T | T[] | undefined>\n\nconst open = useVModel(props, 'open', emits, {\n defaultValue: props.defaultOpen,\n passive: (props.open === undefined) as false,\n}) as Ref<boolean>\n\nconst triggerElement = ref<HTMLElement>()\nconst valueElement = ref<HTMLElement>()\nconst triggerPointerDownPosRef = ref({\n x: 0,\n y: 0,\n})\n\nconst isEmptyModelValue = computed(() => {\n if (multiple.value && Array.isArray(modelValue.value))\n return modelValue.value?.length === 0\n else\n return isNullish(modelValue.value)\n})\n\nuseCollection({ isProvider: true })\nconst dir = useDirection(propDir)\n\nconst isFormControl = useFormControl(triggerElement)\nconst optionsSet = ref<Set<SelectOption>>(new Set())\n\n// The native `select` only associates the correct default value if the corresponding\n// `option` is rendered as a child **at the same time** as itself.\n// Because it might take a few renders for our items to gather the information to build\n// the native `option`(s), we generate a key on the `select` to make sure Vue re-builds it\n// each time the options change.\nconst nativeSelectKey = computed(() => {\n return Array.from(optionsSet.value)\n .map(option => option.value)\n .join(';')\n})\n\nfunction handleValueChange(value: T) {\n if (multiple.value) {\n const array = Array.isArray(modelValue.value) ? [...modelValue.value] : []\n const index = array.findIndex(i => compare(i, value, props.by))\n index === -1 ? array.push(value) : array.splice(index, 1)\n modelValue.value = [...array]\n }\n else {\n modelValue.value = value\n }\n}\n\nprovideSelectRootContext({\n triggerElement,\n onTriggerChange: (node) => {\n triggerElement.value = node\n },\n valueElement,\n onValueElementChange: (node) => {\n valueElement.value = node\n },\n contentId: '',\n modelValue,\n // @ts-expect-error Missing infer for AcceptableValue\n onValueChange: handleValueChange,\n by: props.by,\n open,\n multiple,\n required,\n onOpenChange: (value) => {\n open.value = value\n },\n dir,\n triggerPointerDownPosRef,\n disabled,\n isEmptyModelValue,\n\n optionsSet,\n onOptionAdd: option => optionsSet.value.add(option),\n onOptionRemove: option => optionsSet.value.delete(option),\n})\n</script>\n\n<template>\n <PopperRoot>\n <slot\n :model-value=\"modelValue\"\n :open=\"open\"\n />\n\n <BubbleSelect\n v-if=\"isFormControl\"\n :key=\"nativeSelectKey\"\n aria-hidden=\"true\"\n tabindex=\"-1\"\n :multiple=\"multiple\"\n :required=\"required\"\n :name=\"name\"\n :autocomplete=\"autocomplete\"\n :disabled=\"disabled\"\n :value=\"modelValue\"\n >\n <option\n v-if=\"isNullish(modelValue)\"\n value=\"\"\n />\n <option\n v-for=\"option in Array.from(optionsSet)\"\n :key=\"option.value ?? ''\"\n v-bind=\"option\"\n />\n </BubbleSelect>\n </PopperRoot>\n</template>\n"],"names":["createContext","toRefs","useVModel","ref","computed","isNullish","useCollection","useDirection","useFormControl","compare"],"mappings":"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"}