{"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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"}