UNPKG

reka-ui

Version:

Vue port for Radix UI Primitives.

1 lines 14.3 kB
{"version":3,"file":"TagsInputRoot.cjs","sources":["../../src/TagsInput/TagsInputRoot.vue"],"sourcesContent":["<script lang=\"ts\">\nimport type { PrimitiveProps } from '@/Primitive'\nimport { createContext, useArrowNavigation, useDirection, useFormControl, useForwardExpose } from '@/shared'\nimport type { Direction, FormFieldProps } from '@/shared/types'\nimport { type Ref, computed, ref, toRefs } from 'vue'\n\nexport type AcceptableInputValue = string | Record<string, any>\n\nexport interface TagsInputRootProps<T = AcceptableInputValue> extends PrimitiveProps, FormFieldProps {\n /** The controlled value of the tags input. Can be bind as `v-model`. */\n modelValue?: Array<T> | null\n /** The value of the tags that should be added. Use when you do not need to control the state of the tags input */\n defaultValue?: Array<T>\n /** When `true`, allow adding tags on paste. Work in conjunction with delimiter prop. */\n addOnPaste?: boolean\n /** When `true` allow adding tags on tab keydown */\n addOnTab?: boolean\n /** When `true` allow adding tags blur input */\n addOnBlur?: boolean\n /** When `true`, allow duplicated tags. */\n duplicate?: boolean\n /** When `true`, prevents the user from interacting with the tags input. */\n disabled?: boolean\n /** The character or regular expression to trigger the addition of a new tag. Also used to split tags for `@paste` event */\n delimiter?: string | RegExp\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 /** Maximum number of tags. */\n max?: number\n id?: string\n /** Convert the input value to the desired type. Mandatory when using objects as values and using `TagsInputInput` */\n convertValue?: (value: string) => T\n /** Display the value of the tag. Useful when you want to apply modifications to the value like adding a suffix or when using object as values */\n displayValue?: (value: T) => string\n}\n\nexport type TagsInputRootEmits<T = AcceptableInputValue> = {\n /** Event handler called when the value changes */\n 'update:modelValue': [payload: Array<T>]\n /** Event handler called when the value is invalid */\n 'invalid': [payload: T]\n /** Event handler called when tag is added */\n 'addTag': [payload: T]\n /** Event handler called when tag is removed */\n 'removeTag': [payload: T]\n}\n\nexport interface TagsInputRootContext<T = AcceptableInputValue> {\n modelValue: Ref<Array<T>>\n onAddValue: (payload: string) => boolean\n onRemoveValue: (index: number) => void\n onInputKeydown: (event: KeyboardEvent) => void\n selectedElement: Ref<HTMLElement | undefined>\n isInvalidInput: Ref<boolean>\n addOnPaste: Ref<boolean>\n addOnTab: Ref<boolean>\n addOnBlur: Ref<boolean>\n disabled: Ref<boolean>\n delimiter: Ref<string | RegExp>\n dir: Ref<Direction>\n max: Ref<number>\n id: Ref<string | undefined> | undefined\n displayValue: (value: T) => string\n}\n\nexport const [injectTagsInputRootContext, provideTagsInputRootContext]\n = createContext<TagsInputRootContext>('TagsInputRoot')\n</script>\n\n<script setup lang=\"ts\" generic=\"T extends AcceptableInputValue = string\">\nimport { Primitive } from '@/Primitive'\nimport { useCollection } from '@/Collection'\nimport { useFocusWithin, useVModel } from '@vueuse/core'\nimport { VisuallyHiddenInput } from '@/VisuallyHidden'\n\nconst props = withDefaults(defineProps<TagsInputRootProps<T>>(), {\n defaultValue: () => [],\n delimiter: ',',\n max: 0,\n displayValue: (value: T) => value.toString(),\n})\nconst emits = defineEmits<TagsInputRootEmits<T>>()\n\ndefineSlots<{\n default: (props: {\n /** Current input values */\n modelValue: typeof modelValue.value\n }) => any\n}>()\n\nconst { addOnPaste, disabled, delimiter, max, id, dir: propDir, addOnBlur, addOnTab } = toRefs(props)\nconst dir = useDirection(propDir)\n\nconst modelValue = useVModel(props, 'modelValue', emits, {\n defaultValue: props.defaultValue,\n passive: true,\n deep: true,\n}) as Ref<Array<AcceptableInputValue>>\n\nconst { forwardRef, currentElement } = useForwardExpose()\nconst { focused } = useFocusWithin(currentElement)\nconst isFormControl = useFormControl(currentElement)\n\nconst { getItems, CollectionSlot } = useCollection({ isProvider: true })\n\nconst selectedElement = ref<HTMLElement>()\nconst isInvalidInput = ref(false)\n\nconst currentModelValue = computed(() => Array.isArray(modelValue.value) ? [...modelValue.value] : [])\n\nfunction handleRemoveTag(index: number) {\n if (index !== -1) {\n const collection = getItems().filter(i => i.ref.dataset.disabled !== '')\n modelValue.value = modelValue.value.filter((_, i) => i !== index)\n emits('removeTag', collection[index].value)\n }\n}\n\nprovideTagsInputRootContext({\n modelValue,\n onAddValue: (_payload) => {\n const array = [...currentModelValue.value]\n const modelValueIsObject = array.length > 0 && typeof array[0] === 'object'\n const defaultValueIsObject = array.length > 0 && typeof props.defaultValue[0] === 'object'\n\n // Check if the value is an object and if the convertValue function is provided. We don't check this a type level because the use\n // of `TagsInputInput` is optional.\n if ((modelValueIsObject || defaultValueIsObject) && typeof props.convertValue !== 'function')\n throw new Error('You must provide a `convertValue` function when using objects as values.')\n const payload = props.convertValue ? props.convertValue(_payload) : _payload as T\n\n if ((array.length >= max.value) && !!max.value) {\n emits('invalid', payload)\n return false\n }\n\n if (props.duplicate) {\n modelValue.value = [...array, payload]\n emits('addTag', payload)\n return true\n }\n else {\n const exist = array.includes(payload)\n if (!exist) {\n modelValue.value = [...array, payload]\n emits('addTag', payload)\n return true\n }\n else {\n isInvalidInput.value = true\n }\n }\n emits('invalid', payload)\n return false\n },\n onRemoveValue: handleRemoveTag,\n onInputKeydown: (event) => {\n const target = event.target as HTMLInputElement\n const collection = getItems().map(i => i.ref).filter(i => i.dataset.disabled !== '')\n if (!collection.length)\n return\n const lastTag = collection.at(-1)\n switch (event.key) {\n case 'Delete':\n case 'Backspace': {\n if (target.selectionStart !== 0 || target.selectionEnd !== 0)\n break\n\n if (selectedElement.value) {\n const index = collection.findIndex(i => i === selectedElement.value)\n handleRemoveTag(index)\n selectedElement.value = selectedElement.value === lastTag ? collection.at(index - 1) : collection.at(index + 1)\n event.preventDefault()\n }\n else if (event.key === 'Backspace') {\n selectedElement.value = lastTag\n event.preventDefault()\n }\n break\n }\n case 'Home':\n case 'End':\n case 'ArrowRight':\n case 'ArrowLeft': {\n const isArrowRight = (event.key === 'ArrowRight' && dir.value === 'ltr') || (event.key === 'ArrowLeft' && dir.value === 'rtl')\n const isArrowLeft = !isArrowRight\n // only focus on tags when cursor is at the first position\n if (target.selectionStart !== 0 || target.selectionEnd !== 0)\n break\n\n // if you press ArrowLeft, then we last tag\n if (isArrowLeft && !selectedElement.value) {\n selectedElement.value = lastTag\n event.preventDefault()\n }\n // if you press ArrowRight on last tag, you deselect\n else if (isArrowRight && lastTag && selectedElement.value === lastTag) {\n selectedElement.value = undefined\n event.preventDefault()\n }\n else if (selectedElement.value) {\n const el = useArrowNavigation(event, selectedElement.value, undefined, {\n itemsArray: collection,\n loop: false,\n dir: dir.value,\n })\n if (el)\n selectedElement.value = el\n event.preventDefault()\n }\n break\n }\n case 'ArrowUp':\n case 'ArrowDown': {\n if (selectedElement.value)\n event.preventDefault()\n break\n }\n default: {\n selectedElement.value = undefined\n }\n }\n },\n selectedElement,\n isInvalidInput,\n addOnPaste,\n addOnBlur,\n addOnTab,\n dir,\n disabled,\n delimiter,\n max,\n id,\n displayValue: props.displayValue as (value: AcceptableInputValue) => string,\n})\n</script>\n\n<template>\n <CollectionSlot>\n <Primitive\n :ref=\"forwardRef\"\n :dir=\"dir\"\n :as=\"as\"\n :as-child=\"asChild\"\n :data-invalid=\"isInvalidInput ? '' : undefined\"\n :data-disabled=\"disabled ? '' : undefined\"\n :data-focused=\"focused ? '' : undefined\"\n >\n <slot :model-value=\"modelValue\" />\n\n <VisuallyHiddenInput\n v-if=\"isFormControl && name\"\n :name=\"name\"\n :value=\"modelValue\"\n :required=\"required\"\n :disabled=\"disabled\"\n />\n </Primitive>\n </CollectionSlot>\n</template>\n"],"names":["createContext","toRefs","useDirection","useVModel","useForwardExpose","useFocusWithin","useFormControl","useCollection","ref","computed","useArrowNavigation"],"mappings":"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"}