@milaboratories/uikit 2.16.3 → 2.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +30 -22
- package/.turbo/turbo-formatter$colon$check.log +1 -1
- package/.turbo/turbo-linter$colon$check.log +1 -1
- package/CHANGELOG.md +26 -0
- package/dist/components/PlAlert/PlAlert.js.map +1 -1
- package/dist/components/PlAlert/PlAlert.vue.d.ts +4 -1
- package/dist/components/PlAlert/PlAlert.vue.d.ts.map +1 -1
- package/dist/components/PlAlert/PlAlert.vue2.js +19 -18
- package/dist/components/PlAlert/PlAlert.vue2.js.map +1 -1
- package/dist/components/PlDropdown/PlDropdown.js +5 -4
- package/dist/components/PlDropdown/PlDropdown.js.map +1 -1
- package/dist/components/PlDropdown/PlDropdown.style.css +1 -0
- package/dist/components/PlDropdown/PlDropdown.style.js +5 -0
- package/dist/components/PlDropdown/PlDropdown.style.js.map +1 -0
- package/dist/components/PlDropdown/PlDropdown.vue.d.ts +10 -2
- package/dist/components/PlDropdown/PlDropdown.vue.d.ts.map +1 -1
- package/dist/components/PlDropdown/PlDropdown.vue2.js +136 -110
- package/dist/components/PlDropdown/PlDropdown.vue2.js.map +1 -1
- package/dist/components/PlDropdownMulti/PlDropdownMulti.js.map +1 -1
- package/dist/components/PlDropdownMulti/PlDropdownMulti.vue.d.ts +10 -2
- package/dist/components/PlDropdownMulti/PlDropdownMulti.vue.d.ts.map +1 -1
- package/dist/components/PlDropdownMulti/PlDropdownMulti.vue2.js +123 -84
- package/dist/components/PlDropdownMulti/PlDropdownMulti.vue2.js.map +1 -1
- package/dist/components/PlDropdownMultiRef/PlDropdownMultiRef.js.map +1 -1
- package/dist/components/PlDropdownMultiRef/PlDropdownMultiRef.vue.d.ts +12 -5
- package/dist/components/PlDropdownMultiRef/PlDropdownMultiRef.vue.d.ts.map +1 -1
- package/dist/components/PlDropdownMultiRef/PlDropdownMultiRef.vue2.js +8 -1
- package/dist/components/PlDropdownMultiRef/PlDropdownMultiRef.vue2.js.map +1 -1
- package/dist/components/PlDropdownRef/PlDropdownRef.js.map +1 -1
- package/dist/components/PlDropdownRef/PlDropdownRef.vue.d.ts +8 -2
- package/dist/components/PlDropdownRef/PlDropdownRef.vue.d.ts.map +1 -1
- package/dist/components/PlDropdownRef/PlDropdownRef.vue2.js +8 -1
- package/dist/components/PlDropdownRef/PlDropdownRef.vue2.js.map +1 -1
- package/dist/components/PlTooltip/PlTooltip.js.map +1 -1
- package/dist/components/PlTooltip/PlTooltip.style.css +1 -1
- package/dist/components/PlTooltip/PlTooltip.style.js +1 -1
- package/dist/components/PlTooltip/PlTooltip.style.js.map +1 -1
- package/dist/components/PlTooltip/PlTooltip.vue.d.ts.map +1 -1
- package/dist/components/PlTooltip/PlTooltip.vue2.js +1 -1
- package/dist/components/PlTooltip/PlTooltip.vue2.js.map +1 -1
- package/dist/components/PlValueLabel/PlValueLabel.js +7 -0
- package/dist/components/PlValueLabel/PlValueLabel.js.map +1 -0
- package/dist/components/PlValueLabel/PlValueLabel.style.css +1 -0
- package/dist/components/PlValueLabel/PlValueLabel.style.js +5 -0
- package/dist/components/PlValueLabel/PlValueLabel.style.js.map +1 -0
- package/dist/components/PlValueLabel/PlValueLabel.vue.d.ts +45 -0
- package/dist/components/PlValueLabel/PlValueLabel.vue.d.ts.map +1 -0
- package/dist/components/PlValueLabel/PlValueLabel.vue2.js +37 -0
- package/dist/components/PlValueLabel/PlValueLabel.vue2.js.map +1 -0
- package/dist/components/PlValueLabel/__tests__/PlValueLabel.spec.d.ts +2 -0
- package/dist/components/PlValueLabel/__tests__/PlValueLabel.spec.d.ts.map +1 -0
- package/dist/components/PlValueLabel/index.d.ts +2 -0
- package/dist/components/PlValueLabel/index.d.ts.map +1 -0
- package/dist/components/PlValueLabel/index.js +1 -0
- package/dist/helpers/columnValue.d.ts +25 -0
- package/dist/helpers/columnValue.d.ts.map +1 -0
- package/dist/helpers/columnValue.js +17 -0
- package/dist/helpers/columnValue.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +32 -30
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/components/PlAlert/PlAlert.vue +13 -2
- package/src/components/PlDropdown/PlDropdown.vue +49 -8
- package/src/components/PlDropdown/__tests__/PlDropdown.spec.ts +95 -0
- package/src/components/PlDropdownMulti/PlDropdownMulti.vue +50 -9
- package/src/components/PlDropdownMulti/__tests__/PlDropdownMulti.spec.ts +47 -0
- package/src/components/PlDropdownMultiRef/PlDropdownMultiRef.vue +10 -3
- package/src/components/PlDropdownMultiRef/__tests__/PlDropdownMultiRef.spec.ts +2 -2
- package/src/components/PlDropdownRef/PlDropdownRef.vue +10 -3
- package/src/components/PlDropdownRef/__tests__/PlDropdownRef.spec.ts +2 -2
- package/src/components/PlTooltip/PlTooltip.vue +1 -0
- package/src/components/PlValueLabel/PlValueLabel.vue +80 -0
- package/src/components/PlValueLabel/__tests__/PlValueLabel.spec.ts +64 -0
- package/src/components/PlValueLabel/index.ts +1 -0
- package/src/helpers/columnValue.ts +43 -0
- package/src/index.ts +2 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlDropdownMulti.js","names":["_sfc_main","PlDropdownMulti_vue_vue_type_script_setup_true_lang_default","PlDropdownMulti_default"],"sources":["../../../src/components/PlDropdownMulti/PlDropdownMulti.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * A component for selecting multiple values from a list of options\n */\nexport default {\n name: \"PlDropdownMulti\",\n};\n</script>\n\n<script lang=\"ts\" setup generic=\"M = unknown\">\nimport {\n computed,\n reactive,\n ref,\n unref,\n useSlots,\n useTemplateRef,\n watch,\n watchPostEffect,\n} from \"vue\";\nimport SvgRequired from \"../../assets/images/required.svg?raw\";\nimport { getErrorMessage } from \"../../helpers/error.ts\";\nimport { deepEqual, deepIncludes } from \"../../helpers/objects\";\nimport { normalizeListOptions } from \"../../helpers/utils\";\nimport type { ListOption } from \"../../types\";\nimport DoubleContour from \"../../utils/DoubleContour.vue\";\nimport DropdownOverlay from \"../../utils/DropdownOverlay/DropdownOverlay.vue\";\nimport { useLabelNotch } from \"../../utils/useLabelNotch\";\nimport DropdownListItem from \"../DropdownListItem.vue\";\nimport { PlChip } from \"../PlChip\";\nimport { PlIcon24 } from \"../PlIcon24\";\nimport { PlSvg } from \"../PlSvg\";\nimport { PlTooltip } from \"../PlTooltip\";\nimport \"./pl-dropdown-multi.scss\";\n\nconst emit = defineEmits<{\n (e: \"update:modelValue\", v: M[]): void;\n}>();\n\nconst emitModel = (v: M[]) => emit(\"update:modelValue\", v);\n\nconst slots = useSlots();\n\nconst props = withDefaults(\n defineProps<{\n /**\n * The current selected values.\n */\n modelValue: M[];\n /**\n * The label text for the dropdown field (optional)\n */\n label?: string;\n /**\n * List of available options for the dropdown\n */\n options?: Readonly<ListOption<M>[]>;\n /**\n * A helper text displayed below the dropdown when there are no errors (optional).\n */\n helper?: string;\n /**\n * Error message displayed below the dropdown (optional)\n */\n error?: unknown;\n /**\n * Placeholder text shown when no value is selected.\n */\n placeholder?: string;\n /**\n * Text shown in a chip when a `modelValue` entry is missing from `options` —\n * e.g. its upstream source was deleted. Rendered italic in error color.\n */\n missingValueLabel?: string;\n /**\n * If `true`, the dropdown component is marked as required.\n */\n required?: boolean;\n /**\n * If `true`, the dropdown component is disabled and cannot be interacted with.\n */\n disabled?: boolean;\n /**\n * Makes some of corners not rounded\n * */\n groupPosition?:\n | \"top\"\n | \"bottom\"\n | \"left\"\n | \"right\"\n | \"top-left\"\n | \"top-right\"\n | \"bottom-left\"\n | \"bottom-right\"\n | \"middle\";\n }>(),\n {\n modelValue: () => [],\n label: undefined,\n helper: undefined,\n error: undefined,\n placeholder: \"...\",\n missingValueLabel: \"Value not available\",\n required: false,\n disabled: false,\n options: undefined,\n groupPosition: undefined,\n },\n);\n\nconst rootRef = ref<HTMLElement | undefined>();\nconst input = ref<HTMLInputElement | undefined>();\n\nconst overlay = useTemplateRef(\"overlay\");\n\nconst data = reactive({\n search: \"\",\n activeOption: -1,\n open: false,\n optionsHeight: 0,\n});\n\nconst selectedValuesRef = computed(() => (Array.isArray(props.modelValue) ? props.modelValue : []));\n\nconst placeholderRef = computed(() => {\n if (data.open && props.modelValue.length > 0) {\n return props.placeholder;\n }\n\n return props.modelValue.length > 0 ? \"\" : props.placeholder;\n});\n\nconst normalizedOptionsRef = computed(() => normalizeListOptions(props.options ?? []));\n\nconst selectedOptionsRef = computed(() => {\n // While options load (`options === undefined`), hide chips for unresolved values\n // to avoid a \"missing\" flash that resolves once options arrive.\n const optionsLoaded = props.options !== undefined;\n return selectedValuesRef.value\n .map((v) => {\n const opt = normalizedOptionsRef.value.find((o) => deepEqual(o.value, v));\n if (opt) {\n // Found: render the option's own (normalized) label verbatim — matches\n // PlDropdown. `opt.label` is always a string (possibly \"\"), never an object,\n // so there is no raw-value leak to guard against.\n return { ...opt, isMissing: false };\n }\n if (!optionsLoaded) {\n return undefined;\n }\n // Honor empty `missingValueLabel` verbatim — caller's explicit \"render nothing\".\n return {\n value: v,\n label: props.missingValueLabel,\n isMissing: true,\n };\n })\n .filter((v): v is NonNullable<typeof v> => v !== undefined);\n});\n\nconst filteredOptionsRef = computed(() => {\n const selectedValues = unref(selectedValuesRef);\n\n const options = unref(normalizedOptionsRef);\n\n return (\n data.search\n ? options.filter((opt) => {\n const search = data.search.toLowerCase();\n\n if (opt.label.toLowerCase().includes(search)) {\n return true;\n }\n\n if (typeof opt.value === \"string\") {\n return opt.value.toLowerCase().includes(search);\n }\n\n return opt.value === data.search;\n })\n : [...options]\n ).map((opt) => ({\n ...opt,\n selected: deepIncludes(selectedValues, opt.value),\n }));\n});\n\nconst isLoadingOptions = computed(() => {\n return props.options === undefined;\n});\n\nconst showLoadingSpinner = computed(() => {\n return !props.disabled && isLoadingOptions.value;\n});\n\nconst isDisabled = computed(() => {\n if (isLoadingOptions.value) {\n return true;\n }\n\n return props.disabled;\n});\n\nconst tabindex = computed(() => (isDisabled.value ? undefined : \"0\"));\n\nconst updateActiveOption = () => {\n data.activeOption = 0;\n};\n\nconst selectOption = (v: M) => {\n const values = unref(selectedValuesRef);\n emitModel(deepIncludes(values, v) ? values.filter((it) => !deepEqual(it, v)) : [...values, v]);\n data.search = \"\";\n rootRef?.value?.focus();\n};\n\nconst unselectOption = (d: M) =>\n emitModel(unref(selectedValuesRef).filter((v) => !deepEqual(v, d)));\n\nconst setFocusOnInput = () => input.value?.focus();\n\nconst toggleModel = () => {\n data.open = !data.open;\n if (!data.open) {\n data.search = \"\";\n }\n};\n\nconst onFocusOut = (event: FocusEvent) => {\n const relatedTarget = event.relatedTarget as Node | null;\n\n if (!rootRef.value?.contains(relatedTarget) && !overlay.value?.listRef?.contains(relatedTarget)) {\n data.search = \"\";\n data.open = false;\n }\n};\n\nconst handleKeydown = (e: { code: string; preventDefault(): void }) => {\n const { open, activeOption } = data;\n\n if (!open) {\n if (e.code === \"Enter\") {\n data.open = true;\n }\n return;\n }\n\n if (e.code === \"Escape\") {\n data.open = false;\n rootRef.value?.focus();\n }\n\n const filteredOptions = unref(filteredOptionsRef);\n\n const { length } = filteredOptions;\n\n if (!length) {\n return;\n }\n\n if ([\"ArrowDown\", \"ArrowUp\", \"Enter\"].includes(e.code)) {\n e.preventDefault();\n }\n\n if (e.code === \"Enter\") {\n selectOption(filteredOptions[activeOption].value);\n }\n\n const d = e.code === \"ArrowDown\" ? 1 : e.code === \"ArrowUp\" ? -1 : 0;\n\n data.activeOption = Math.abs(activeOption + d + length) % length;\n\n requestAnimationFrame(() => overlay.value?.scrollIntoActive());\n};\n\nuseLabelNotch(rootRef);\n\nwatch(\n () => props.modelValue,\n () => updateActiveOption(),\n { immediate: true },\n);\n\nwatchPostEffect(() => {\n // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n data.search;\n\n if (data.open) {\n overlay.value?.scrollIntoActive();\n }\n});\n</script>\n\n<template>\n <div class=\"pl-dropdown-multi__envelope\" @click=\"setFocusOnInput\" data-testid=\"pl-dropdown-multi\">\n <div\n ref=\"rootRef\"\n :tabindex=\"tabindex\"\n class=\"pl-dropdown-multi\"\n data-testid=\"pl-dropdown-multi-control\"\n :class=\"{ open: data.open, error, disabled: isDisabled }\"\n @keydown=\"handleKeydown\"\n @focusout=\"onFocusOut\"\n >\n <div class=\"pl-dropdown-multi__container\">\n <div class=\"pl-dropdown-multi__field\">\n <input\n ref=\"input\"\n v-model=\"data.search\"\n type=\"text\"\n tabindex=\"-1\"\n :disabled=\"isDisabled\"\n :placeholder=\"placeholderRef\"\n spellcheck=\"false\"\n autocomplete=\"chrome-off\"\n data-testid=\"pl-dropdown-multi-input\"\n @focus=\"data.open = true\"\n />\n <div v-if=\"!data.open\" class=\"chips-container\" data-testid=\"pl-dropdown-multi-chips\">\n <PlChip\n v-for=\"(opt, i) in selectedOptionsRef\"\n :key=\"i\"\n :class=\"{ 'pl-dropdown-multi__chip--missing': opt.isMissing }\"\n closeable\n data-testid=\"pl-dropdown-multi-chip\"\n small\n @click.stop=\"data.open = true\"\n @close=\"unselectOption(opt.value)\"\n >\n {{ opt.label }}\n </PlChip>\n </div>\n\n <div class=\"pl-dropdown-multi__controls\">\n <PlIcon24\n v-if=\"showLoadingSpinner\"\n name=\"loading\"\n data-testid=\"pl-dropdown-multi-loading\"\n />\n <slot name=\"append\" />\n <div\n class=\"pl-dropdown-multi__arrow-wrapper\"\n data-testid=\"pl-dropdown-multi-arrow\"\n @click.stop=\"toggleModel\"\n >\n <div class=\"arrow-icon arrow-icon-default\" />\n </div>\n </div>\n </div>\n <label v-if=\"label\" data-testid=\"pl-dropdown-multi-label\">\n <PlSvg v-if=\"required\" :uri=\"SvgRequired\" data-testid=\"pl-dropdown-multi-required\" />\n <span>{{ label }}</span>\n <PlTooltip\n v-if=\"slots.tooltip\"\n class=\"info\"\n position=\"top\"\n data-testid=\"pl-dropdown-multi-tooltip\"\n >\n <template #tooltip>\n <slot name=\"tooltip\" />\n </template>\n </PlTooltip>\n </label>\n <DropdownOverlay\n v-if=\"data.open\"\n ref=\"overlay\"\n :root=\"rootRef\"\n class=\"pl-dropdown-multi__options\"\n data-testid=\"pl-dropdown-multi-options\"\n :gap=\"5\"\n tabindex=\"-1\"\n @focusout=\"onFocusOut\"\n >\n <div\n class=\"pl-dropdown-multi__open-chips-container\"\n data-testid=\"pl-dropdown-multi-chips\"\n >\n <PlChip\n v-for=\"(opt, i) in selectedOptionsRef\"\n :key=\"i\"\n :class=\"{ 'pl-dropdown-multi__chip--missing': opt.isMissing }\"\n closeable\n data-testid=\"pl-dropdown-multi-chip\"\n small\n @close=\"unselectOption(opt.value)\"\n >\n {{ opt.label }}\n </PlChip>\n </div>\n <DropdownListItem\n v-for=\"(item, index) in filteredOptionsRef\"\n :key=\"index\"\n :option=\"item\"\n :text-item=\"'text'\"\n :is-selected=\"item.selected\"\n :is-hovered=\"data.activeOption == index\"\n size=\"medium\"\n use-checkbox\n data-testid=\"pl-dropdown-multi-option\"\n @click.stop=\"selectOption(item.value)\"\n />\n <div\n v-if=\"!filteredOptionsRef.length\"\n class=\"nothing-found\"\n data-testid=\"pl-dropdown-multi-options-empty\"\n >\n Nothing found\n </div>\n </DropdownOverlay>\n <DoubleContour class=\"pl-dropdown-multi__contour\" :group-position=\"groupPosition\" />\n </div>\n </div>\n <div v-if=\"error\" class=\"pl-dropdown-multi__error\" data-testid=\"pl-dropdown-multi-error\">\n {{ getErrorMessage(error) }}\n </div>\n <div\n v-else-if=\"helper\"\n class=\"pl-dropdown-multi__helper\"\n data-testid=\"pl-dropdown-multi-helper\"\n >\n {{ helper }}\n </div>\n </div>\n</template>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"PlDropdownMulti.js","names":["_sfc_main","PlDropdownMulti_vue_vue_type_script_setup_true_lang_default","PlDropdownMulti_default"],"sources":["../../../src/components/PlDropdownMulti/PlDropdownMulti.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * A component for selecting multiple values from a list of options\n */\nexport default {\n name: \"PlDropdownMulti\",\n};\n</script>\n\n<script lang=\"ts\" setup generic=\"M = unknown\">\nimport {\n computed,\n reactive,\n ref,\n unref,\n useSlots,\n useTemplateRef,\n watch,\n watchPostEffect,\n} from \"vue\";\nimport SvgRequired from \"../../assets/images/required.svg?raw\";\nimport { missingValueText, missingValueTooltip, pickedValueText } from \"../../helpers/columnValue\";\nimport type { MissingValueLabel, MissingValueTooltip } from \"../../helpers/columnValue\";\nimport { getErrorMessage } from \"../../helpers/error.ts\";\nimport { deepEqual, deepIncludes } from \"../../helpers/objects\";\nimport { normalizeListOptions } from \"../../helpers/utils\";\nimport type { ListOption } from \"../../types\";\nimport DoubleContour from \"../../utils/DoubleContour.vue\";\nimport DropdownOverlay from \"../../utils/DropdownOverlay/DropdownOverlay.vue\";\nimport { useLabelNotch } from \"../../utils/useLabelNotch\";\nimport DropdownListItem from \"../DropdownListItem.vue\";\nimport { PlChip } from \"../PlChip\";\nimport { PlIcon24 } from \"../PlIcon24\";\nimport { PlSvg } from \"../PlSvg\";\nimport { PlTooltip } from \"../PlTooltip\";\nimport \"./pl-dropdown-multi.scss\";\n\nconst emit = defineEmits<{\n (e: \"update:modelValue\", v: M[]): void;\n}>();\n\nconst emitModel = (v: M[]) => emit(\"update:modelValue\", v);\n\nconst slots = useSlots();\n\nconst props = withDefaults(\n defineProps<{\n /**\n * The current selected values.\n */\n modelValue: M[];\n /**\n * The label text for the dropdown field (optional)\n */\n label?: string;\n /**\n * List of available options for the dropdown\n */\n options?: Readonly<ListOption<M>[]>;\n /**\n * A helper text displayed below the dropdown when there are no errors (optional).\n */\n helper?: string;\n /**\n * Error message displayed below the dropdown (optional)\n */\n error?: unknown;\n /**\n * Placeholder text shown when no value is selected.\n */\n placeholder?: string;\n /**\n * Text shown in a chip when a `modelValue` entry is missing from `options` —\n * e.g. its upstream source was deleted. Rendered italic in error color. One text for every\n * such value, or a function giving it per value. By default, the value a column value id\n * picks, marked as not available, or \"Value not available\".\n */\n missingValueLabel?: MissingValueLabel;\n /**\n * Explains a selected value missing from the options in a tooltip over it: one text for every\n * such value, or a function giving the content per value.\n */\n missingValueTooltip?: MissingValueTooltip;\n /**\n * If `true`, the dropdown component is marked as required.\n */\n required?: boolean;\n /**\n * If `true`, the dropdown component is disabled and cannot be interacted with.\n */\n disabled?: boolean;\n /**\n * Makes some of corners not rounded\n * */\n groupPosition?:\n | \"top\"\n | \"bottom\"\n | \"left\"\n | \"right\"\n | \"top-left\"\n | \"top-right\"\n | \"bottom-left\"\n | \"bottom-right\"\n | \"middle\";\n }>(),\n {\n modelValue: () => [],\n label: undefined,\n helper: undefined,\n error: undefined,\n placeholder: \"...\",\n missingValueLabel: undefined,\n missingValueTooltip: undefined,\n required: false,\n disabled: false,\n options: undefined,\n groupPosition: undefined,\n },\n);\n\nconst rootRef = ref<HTMLElement | undefined>();\nconst input = ref<HTMLInputElement | undefined>();\n\nconst overlay = useTemplateRef(\"overlay\");\n\nconst data = reactive({\n search: \"\",\n activeOption: -1,\n open: false,\n optionsHeight: 0,\n});\n\nconst selectedValuesRef = computed(() => (Array.isArray(props.modelValue) ? props.modelValue : []));\n\nconst placeholderRef = computed(() => {\n if (data.open && props.modelValue.length > 0) {\n return props.placeholder;\n }\n\n return props.modelValue.length > 0 ? \"\" : props.placeholder;\n});\n\nconst normalizedOptionsRef = computed(() => normalizeListOptions(props.options ?? []));\n\nconst selectedOptionsRef = computed(() => {\n // While options load (`options === undefined`), hide chips for unresolved values\n // to avoid a \"missing\" flash that resolves once options arrive. A picked column value\n // is shown by its own label meanwhile.\n const optionsLoaded = props.options !== undefined;\n return selectedValuesRef.value\n .map((v) => {\n const opt = normalizedOptionsRef.value.find((o) => deepEqual(o.value, v));\n if (opt) {\n // Found: render the option's own (normalized) label verbatim — matches\n // PlDropdown. `opt.label` is always a string (possibly \"\"), never an object,\n // so there is no raw-value leak to guard against.\n return { ...opt, isMissing: false, hint: undefined };\n }\n if (!optionsLoaded) {\n const label = pickedValueText(v);\n return label === undefined\n ? undefined\n : { value: v, label, isMissing: false, hint: undefined };\n }\n // Honor empty `missingValueLabel` verbatim — caller's explicit \"render nothing\".\n return {\n value: v,\n label: missingValueText(v, props.missingValueLabel),\n isMissing: true,\n hint: missingValueTooltip(v, props.missingValueTooltip),\n };\n })\n .filter((v): v is NonNullable<typeof v> => v !== undefined);\n});\n\nconst filteredOptionsRef = computed(() => {\n const selectedValues = unref(selectedValuesRef);\n\n const options = unref(normalizedOptionsRef);\n\n return (\n data.search\n ? options.filter((opt) => {\n const search = data.search.toLowerCase();\n\n if (opt.label.toLowerCase().includes(search)) {\n return true;\n }\n\n if (typeof opt.value === \"string\") {\n return opt.value.toLowerCase().includes(search);\n }\n\n return opt.value === data.search;\n })\n : [...options]\n ).map((opt) => ({\n ...opt,\n selected: deepIncludes(selectedValues, opt.value),\n }));\n});\n\nconst isLoadingOptions = computed(() => {\n return props.options === undefined;\n});\n\nconst showLoadingSpinner = computed(() => {\n return !props.disabled && isLoadingOptions.value;\n});\n\nconst isDisabled = computed(() => {\n if (isLoadingOptions.value) {\n return true;\n }\n\n return props.disabled;\n});\n\nconst tabindex = computed(() => (isDisabled.value ? undefined : \"0\"));\n\nconst updateActiveOption = () => {\n data.activeOption = 0;\n};\n\nconst selectOption = (v: M) => {\n const values = unref(selectedValuesRef);\n emitModel(deepIncludes(values, v) ? values.filter((it) => !deepEqual(it, v)) : [...values, v]);\n data.search = \"\";\n rootRef?.value?.focus();\n};\n\nconst unselectOption = (d: M) =>\n emitModel(unref(selectedValuesRef).filter((v) => !deepEqual(v, d)));\n\nconst setFocusOnInput = () => input.value?.focus();\n\nconst toggleModel = () => {\n data.open = !data.open;\n if (!data.open) {\n data.search = \"\";\n }\n};\n\nconst onFocusOut = (event: FocusEvent) => {\n const relatedTarget = event.relatedTarget as Node | null;\n\n if (!rootRef.value?.contains(relatedTarget) && !overlay.value?.listRef?.contains(relatedTarget)) {\n data.search = \"\";\n data.open = false;\n }\n};\n\nconst handleKeydown = (e: { code: string; preventDefault(): void }) => {\n const { open, activeOption } = data;\n\n if (!open) {\n if (e.code === \"Enter\") {\n data.open = true;\n }\n return;\n }\n\n if (e.code === \"Escape\") {\n data.open = false;\n rootRef.value?.focus();\n }\n\n const filteredOptions = unref(filteredOptionsRef);\n\n const { length } = filteredOptions;\n\n if (!length) {\n return;\n }\n\n if ([\"ArrowDown\", \"ArrowUp\", \"Enter\"].includes(e.code)) {\n e.preventDefault();\n }\n\n if (e.code === \"Enter\") {\n selectOption(filteredOptions[activeOption].value);\n }\n\n const d = e.code === \"ArrowDown\" ? 1 : e.code === \"ArrowUp\" ? -1 : 0;\n\n data.activeOption = Math.abs(activeOption + d + length) % length;\n\n requestAnimationFrame(() => overlay.value?.scrollIntoActive());\n};\n\nuseLabelNotch(rootRef);\n\nwatch(\n () => props.modelValue,\n () => updateActiveOption(),\n { immediate: true },\n);\n\nwatchPostEffect(() => {\n // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n data.search;\n\n if (data.open) {\n overlay.value?.scrollIntoActive();\n }\n});\n</script>\n\n<template>\n <div class=\"pl-dropdown-multi__envelope\" @click=\"setFocusOnInput\" data-testid=\"pl-dropdown-multi\">\n <div\n ref=\"rootRef\"\n :tabindex=\"tabindex\"\n class=\"pl-dropdown-multi\"\n data-testid=\"pl-dropdown-multi-control\"\n :class=\"{ open: data.open, error, disabled: isDisabled }\"\n @keydown=\"handleKeydown\"\n @focusout=\"onFocusOut\"\n >\n <div class=\"pl-dropdown-multi__container\">\n <div class=\"pl-dropdown-multi__field\">\n <input\n ref=\"input\"\n v-model=\"data.search\"\n type=\"text\"\n tabindex=\"-1\"\n :disabled=\"isDisabled\"\n :placeholder=\"placeholderRef\"\n spellcheck=\"false\"\n autocomplete=\"chrome-off\"\n data-testid=\"pl-dropdown-multi-input\"\n @focus=\"data.open = true\"\n />\n <div v-if=\"!data.open\" class=\"chips-container\" data-testid=\"pl-dropdown-multi-chips\">\n <PlChip\n v-for=\"(opt, i) in selectedOptionsRef\"\n :key=\"i\"\n :class=\"{ 'pl-dropdown-multi__chip--missing': opt.isMissing }\"\n closeable\n data-testid=\"pl-dropdown-multi-chip\"\n small\n @click.stop=\"data.open = true\"\n @close=\"unselectOption(opt.value)\"\n >\n <!-- The hover stops here: the tooltip of the chip itself would close this one. -->\n <PlTooltip\n v-if=\"opt.hint !== undefined\"\n element=\"span\"\n position=\"top\"\n data-testid=\"pl-dropdown-multi-chip-hint\"\n @mouseover.stop\n >\n <span>{{ opt.label }}</span>\n <template #tooltip>\n <component :is=\"opt.hint\" />\n </template>\n </PlTooltip>\n <template v-else>{{ opt.label }}</template>\n </PlChip>\n </div>\n\n <div class=\"pl-dropdown-multi__controls\">\n <PlIcon24\n v-if=\"showLoadingSpinner\"\n name=\"loading\"\n data-testid=\"pl-dropdown-multi-loading\"\n />\n <slot name=\"append\" />\n <div\n class=\"pl-dropdown-multi__arrow-wrapper\"\n data-testid=\"pl-dropdown-multi-arrow\"\n @click.stop=\"toggleModel\"\n >\n <div class=\"arrow-icon arrow-icon-default\" />\n </div>\n </div>\n </div>\n <label v-if=\"label\" data-testid=\"pl-dropdown-multi-label\">\n <PlSvg v-if=\"required\" :uri=\"SvgRequired\" data-testid=\"pl-dropdown-multi-required\" />\n <span>{{ label }}</span>\n <PlTooltip\n v-if=\"slots.tooltip\"\n class=\"info\"\n position=\"top\"\n data-testid=\"pl-dropdown-multi-tooltip\"\n >\n <template #tooltip>\n <slot name=\"tooltip\" />\n </template>\n </PlTooltip>\n </label>\n <DropdownOverlay\n v-if=\"data.open\"\n ref=\"overlay\"\n :root=\"rootRef\"\n class=\"pl-dropdown-multi__options\"\n data-testid=\"pl-dropdown-multi-options\"\n :gap=\"5\"\n tabindex=\"-1\"\n @focusout=\"onFocusOut\"\n >\n <div\n class=\"pl-dropdown-multi__open-chips-container\"\n data-testid=\"pl-dropdown-multi-chips\"\n >\n <PlChip\n v-for=\"(opt, i) in selectedOptionsRef\"\n :key=\"i\"\n :class=\"{ 'pl-dropdown-multi__chip--missing': opt.isMissing }\"\n closeable\n data-testid=\"pl-dropdown-multi-chip\"\n small\n @close=\"unselectOption(opt.value)\"\n >\n <!-- The hover stops here: the tooltip of the chip itself would close this one. -->\n <PlTooltip\n v-if=\"opt.hint !== undefined\"\n element=\"span\"\n position=\"top\"\n data-testid=\"pl-dropdown-multi-chip-hint\"\n @mouseover.stop\n >\n <span>{{ opt.label }}</span>\n <template #tooltip>\n <component :is=\"opt.hint\" />\n </template>\n </PlTooltip>\n <template v-else>{{ opt.label }}</template>\n </PlChip>\n </div>\n <DropdownListItem\n v-for=\"(item, index) in filteredOptionsRef\"\n :key=\"index\"\n :option=\"item\"\n :text-item=\"'text'\"\n :is-selected=\"item.selected\"\n :is-hovered=\"data.activeOption == index\"\n size=\"medium\"\n use-checkbox\n data-testid=\"pl-dropdown-multi-option\"\n @click.stop=\"selectOption(item.value)\"\n />\n <div\n v-if=\"!filteredOptionsRef.length\"\n class=\"nothing-found\"\n data-testid=\"pl-dropdown-multi-options-empty\"\n >\n Nothing found\n </div>\n </DropdownOverlay>\n <DoubleContour class=\"pl-dropdown-multi__contour\" :group-position=\"groupPosition\" />\n </div>\n </div>\n <div v-if=\"error\" class=\"pl-dropdown-multi__error\" data-testid=\"pl-dropdown-multi-error\">\n {{ getErrorMessage(error) }}\n </div>\n <div\n v-else-if=\"helper\"\n class=\"pl-dropdown-multi__helper\"\n data-testid=\"pl-dropdown-multi-helper\"\n >\n {{ helper }}\n </div>\n </div>\n</template>\n"],"mappings":""}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { MissingValueLabel, MissingValueTooltip } from '../../helpers/columnValue';
|
|
1
2
|
import { ListOption } from '../../types';
|
|
2
3
|
/**
|
|
3
4
|
* A component for selecting multiple values from a list of options
|
|
@@ -32,9 +33,16 @@ declare const __VLS_export: <M = unknown>(__VLS_props: NonNullable<Awaited<typeo
|
|
|
32
33
|
placeholder?: string;
|
|
33
34
|
/**
|
|
34
35
|
* Text shown in a chip when a `modelValue` entry is missing from `options` —
|
|
35
|
-
* e.g. its upstream source was deleted. Rendered italic in error color.
|
|
36
|
+
* e.g. its upstream source was deleted. Rendered italic in error color. One text for every
|
|
37
|
+
* such value, or a function giving it per value. By default, the value a column value id
|
|
38
|
+
* picks, marked as not available, or "Value not available".
|
|
36
39
|
*/
|
|
37
|
-
missingValueLabel?:
|
|
40
|
+
missingValueLabel?: MissingValueLabel;
|
|
41
|
+
/**
|
|
42
|
+
* Explains a selected value missing from the options in a tooltip over it: one text for every
|
|
43
|
+
* such value, or a function giving the content per value.
|
|
44
|
+
*/
|
|
45
|
+
missingValueTooltip?: MissingValueTooltip;
|
|
38
46
|
/**
|
|
39
47
|
* If `true`, the dropdown component is marked as required.
|
|
40
48
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlDropdownMulti.vue.d.ts","sourceRoot":"","sources":["../../../src/components/PlDropdownMulti/PlDropdownMulti.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"PlDropdownMulti.vue.d.ts","sourceRoot":"","sources":["../../../src/components/PlDropdownMulti/PlDropdownMulti.vue"],"names":[],"mappings":"AAgeA,OAAO,KAAK,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAIxF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAS9C,OAAO,0BAA0B,CAAC;AAGlC;;GAEG;wBACkB,OAAO,YAAY;AAAxC,wBAAyC;AAKzC,QAAA,MAAM,YAAY,GAAK,CAAC,GAAG,OAAO,EACjC,aAAa,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,EAC9D,YAAY,mBAAmB,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC,EAC3G,gBAAgB,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,EAClE;WA4vBO,OAAO,KAAK,EAAE,WAAW,GAAG,mBAAmB,CAAC;QAjvBpD;;WAEG;oBACS,CAAC,EAAE;QACf;;WAEG;gBACK,MAAM;QACd;;WAEG;kBACO,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;QACnC;;WAEG;iBACM,MAAM;QACf;;WAEG;gBACK,OAAO;QACf;;WAEG;sBACW,MAAM;QACpB;;;;;WAKG;4BACiB,iBAAiB;QACrC;;;WAGG;8BACmB,mBAAmB;QACzC;;WAEG;mBACQ,OAAO;QAClB;;WAEG;mBACQ,OAAO;QAClB;;aAEK;wBAED,KAAK,GACL,QAAQ,GACR,MAAM,GACN,OAAO,GACP,UAAU,GACV,WAAW,GACX,aAAa,GACb,cAAc,GACd,QAAQ;;;KAyrB2E,CAAC,GAAG,CAAC,OAAO,UAAU,SAAS;QAAE,oBAAoB,EAAE,MAAM,CAAC,CAAA;KAAE,GAAG,CAAC,GAAG,EAAE,CAAC;YAC5J,CAAC,OAAO,EAAE,EAAE,KAAK,IAAI;WACtB,GAAG;;iBAbE,CAAC,KAAK,IAAiB,KAAK,GAAG;;kBAC9B,CAAC,KAAK,IAAiB,KAAK,GAAG;;cAhvBvC,mBAAmB,KAAK,CAAC,EAAE,KAAG,IAAI;EAgwBpC,KACQ,OAAO,KAAK,EAAE,KAAK,GAAG;IAAE,KAAK,CAAC,EAAE,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAA;CAAI,CAAC;AACzF,KAAK,mBAAmB,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,GAAG,GAAG;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAG,GAAG;KAAG,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAG,CAAC,GAAG,EAAE,CAAC"}
|
|
@@ -7,39 +7,40 @@ import r from "../DropdownListItem.js";
|
|
|
7
7
|
import { getErrorMessage as i } from "../../helpers/error.js";
|
|
8
8
|
import a from "../PlIcon24/PlIcon24.js";
|
|
9
9
|
import "../PlIcon24/index.js";
|
|
10
|
-
import
|
|
11
|
-
import { useLabelNotch as
|
|
12
|
-
import { deepEqual as
|
|
13
|
-
import
|
|
14
|
-
import
|
|
15
|
-
import
|
|
10
|
+
import ee from "../../utils/DoubleContour.js";
|
|
11
|
+
import { useLabelNotch as o } from "../../utils/useLabelNotch.js";
|
|
12
|
+
import { deepEqual as s, deepIncludes as c } from "../../helpers/objects.js";
|
|
13
|
+
import te from "../../utils/DropdownOverlay/DropdownOverlay.js";
|
|
14
|
+
import ne from "../../assets/images/required.js";
|
|
15
|
+
import l from "../PlChip/PlChip.js";
|
|
16
16
|
import "../PlChip/index.js";
|
|
17
|
+
import { missingValueText as re, missingValueTooltip as u, pickedValueText as ie } from "../../helpers/columnValue.js";
|
|
17
18
|
import './pl-dropdown-multi.css';/* empty css */
|
|
18
|
-
import { Fragment as
|
|
19
|
+
import { Fragment as d, computed as f, createBlock as p, createCommentVNode as m, createElementBlock as h, createElementVNode as g, createTextVNode as _, createVNode as ae, defineComponent as v, normalizeClass as y, openBlock as b, reactive as oe, ref as x, renderList as S, renderSlot as C, resolveDynamicComponent as w, toDisplayString as T, unref as E, useSlots as se, useTemplateRef as ce, vModelText as le, watch as ue, watchPostEffect as de, withCtx as D, withDirectives as fe, withModifiers as O } from "vue";
|
|
19
20
|
// src/components/PlDropdownMulti/PlDropdownMulti.vue?vue&type=script&setup=true&lang.ts
|
|
20
|
-
var
|
|
21
|
+
var pe = ["tabindex"], me = { class: "pl-dropdown-multi__container" }, he = { class: "pl-dropdown-multi__field" }, ge = ["disabled", "placeholder"], k = {
|
|
21
22
|
key: 0,
|
|
22
23
|
class: "chips-container",
|
|
23
24
|
"data-testid": "pl-dropdown-multi-chips"
|
|
24
|
-
},
|
|
25
|
+
}, A = { class: "pl-dropdown-multi__controls" }, j = {
|
|
25
26
|
key: 0,
|
|
26
27
|
"data-testid": "pl-dropdown-multi-label"
|
|
27
|
-
},
|
|
28
|
+
}, M = {
|
|
28
29
|
class: "pl-dropdown-multi__open-chips-container",
|
|
29
30
|
"data-testid": "pl-dropdown-multi-chips"
|
|
30
|
-
},
|
|
31
|
+
}, N = {
|
|
31
32
|
key: 0,
|
|
32
33
|
class: "nothing-found",
|
|
33
34
|
"data-testid": "pl-dropdown-multi-options-empty"
|
|
34
|
-
},
|
|
35
|
+
}, P = {
|
|
35
36
|
key: 0,
|
|
36
37
|
class: "pl-dropdown-multi__error",
|
|
37
38
|
"data-testid": "pl-dropdown-multi-error"
|
|
38
|
-
},
|
|
39
|
+
}, F = {
|
|
39
40
|
key: 1,
|
|
40
41
|
class: "pl-dropdown-multi__helper",
|
|
41
42
|
"data-testid": "pl-dropdown-multi-helper"
|
|
42
|
-
},
|
|
43
|
+
}, I = /*@__PURE__*/ v({
|
|
43
44
|
name: "PlDropdownMulti",
|
|
44
45
|
props: {
|
|
45
46
|
modelValue: { default: () => [] },
|
|
@@ -48,7 +49,14 @@ var ce = ["tabindex"], le = { class: "pl-dropdown-multi__container" }, ue = { cl
|
|
|
48
49
|
helper: { default: void 0 },
|
|
49
50
|
error: { default: void 0 },
|
|
50
51
|
placeholder: { default: "..." },
|
|
51
|
-
missingValueLabel: {
|
|
52
|
+
missingValueLabel: {
|
|
53
|
+
type: [String, Function],
|
|
54
|
+
default: void 0
|
|
55
|
+
},
|
|
56
|
+
missingValueTooltip: {
|
|
57
|
+
type: [String, Function],
|
|
58
|
+
default: void 0
|
|
59
|
+
},
|
|
52
60
|
required: {
|
|
53
61
|
type: Boolean,
|
|
54
62
|
default: !1
|
|
@@ -60,139 +68,160 @@ var ce = ["tabindex"], le = { class: "pl-dropdown-multi__container" }, ue = { cl
|
|
|
60
68
|
groupPosition: { default: void 0 }
|
|
61
69
|
},
|
|
62
70
|
emits: ["update:modelValue"],
|
|
63
|
-
setup(
|
|
64
|
-
let
|
|
71
|
+
setup(v, { emit: I }) {
|
|
72
|
+
let L = I, R = (e) => L("update:modelValue", e), _e = se(), z = v, B = x(), V = x(), H = ce("overlay"), U = oe({
|
|
65
73
|
search: "",
|
|
66
74
|
activeOption: -1,
|
|
67
75
|
open: !1,
|
|
68
76
|
optionsHeight: 0
|
|
69
|
-
}), W =
|
|
77
|
+
}), W = f(() => Array.isArray(z.modelValue) ? z.modelValue : []), ve = f(() => U.open && z.modelValue.length > 0 ? z.placeholder : z.modelValue.length > 0 ? "" : z.placeholder), G = f(() => t(z.options ?? [])), K = f(() => {
|
|
70
78
|
let e = z.options !== void 0;
|
|
71
79
|
return W.value.map((t) => {
|
|
72
|
-
let n = G.value.find((e) =>
|
|
80
|
+
let n = G.value.find((e) => s(e.value, t));
|
|
73
81
|
if (n) return {
|
|
74
82
|
...n,
|
|
75
|
-
isMissing: !1
|
|
83
|
+
isMissing: !1,
|
|
84
|
+
hint: void 0
|
|
76
85
|
};
|
|
77
|
-
if (e)
|
|
86
|
+
if (!e) {
|
|
87
|
+
let e = ie(t);
|
|
88
|
+
return e === void 0 ? void 0 : {
|
|
89
|
+
value: t,
|
|
90
|
+
label: e,
|
|
91
|
+
isMissing: !1,
|
|
92
|
+
hint: void 0
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
78
96
|
value: t,
|
|
79
|
-
label: z.missingValueLabel,
|
|
80
|
-
isMissing: !0
|
|
97
|
+
label: re(t, z.missingValueLabel),
|
|
98
|
+
isMissing: !0,
|
|
99
|
+
hint: u(t, z.missingValueTooltip)
|
|
81
100
|
};
|
|
82
101
|
}).filter((e) => e !== void 0);
|
|
83
|
-
}), q =
|
|
84
|
-
let e =
|
|
102
|
+
}), q = f(() => {
|
|
103
|
+
let e = E(W), t = E(G);
|
|
85
104
|
return (U.search ? t.filter((e) => {
|
|
86
105
|
let t = U.search.toLowerCase();
|
|
87
106
|
return e.label.toLowerCase().includes(t) ? !0 : typeof e.value == "string" ? e.value.toLowerCase().includes(t) : e.value === U.search;
|
|
88
107
|
}) : [...t]).map((t) => ({
|
|
89
108
|
...t,
|
|
90
|
-
selected:
|
|
109
|
+
selected: c(e, t.value)
|
|
91
110
|
}));
|
|
92
|
-
}), J =
|
|
111
|
+
}), J = f(() => z.options === void 0), ye = f(() => !z.disabled && J.value), Y = f(() => J.value ? !0 : z.disabled), X = f(() => Y.value ? void 0 : "0"), be = () => {
|
|
93
112
|
U.activeOption = 0;
|
|
94
|
-
},
|
|
95
|
-
let t =
|
|
96
|
-
|
|
97
|
-
},
|
|
113
|
+
}, Z = (e) => {
|
|
114
|
+
let t = E(W);
|
|
115
|
+
R(c(t, e) ? t.filter((t) => !s(t, e)) : [...t, e]), U.search = "", B?.value?.focus();
|
|
116
|
+
}, Q = (e) => R(E(W).filter((t) => !s(t, e))), xe = () => V.value?.focus(), Se = () => {
|
|
98
117
|
U.open = !U.open, U.open || (U.search = "");
|
|
99
118
|
}, $ = (e) => {
|
|
100
119
|
let t = e.relatedTarget;
|
|
101
120
|
!B.value?.contains(t) && !H.value?.listRef?.contains(t) && (U.search = "", U.open = !1);
|
|
102
|
-
},
|
|
121
|
+
}, Ce = (e) => {
|
|
103
122
|
let { open: t, activeOption: n } = U;
|
|
104
123
|
if (!t) {
|
|
105
124
|
e.code === "Enter" && (U.open = !0);
|
|
106
125
|
return;
|
|
107
126
|
}
|
|
108
127
|
e.code === "Escape" && (U.open = !1, B.value?.focus());
|
|
109
|
-
let r =
|
|
128
|
+
let r = E(q), { length: i } = r;
|
|
110
129
|
if (!i) return;
|
|
111
130
|
[
|
|
112
131
|
"ArrowDown",
|
|
113
132
|
"ArrowUp",
|
|
114
133
|
"Enter"
|
|
115
|
-
].includes(e.code) && e.preventDefault(), e.code === "Enter" &&
|
|
134
|
+
].includes(e.code) && e.preventDefault(), e.code === "Enter" && Z(r[n].value);
|
|
116
135
|
let a = e.code === "ArrowDown" ? 1 : e.code === "ArrowUp" ? -1 : 0;
|
|
117
136
|
U.activeOption = Math.abs(n + a + i) % i, requestAnimationFrame(() => H.value?.scrollIntoActive());
|
|
118
137
|
};
|
|
119
|
-
return
|
|
138
|
+
return o(B), ue(() => z.modelValue, () => be(), { immediate: !0 }), de(() => {
|
|
120
139
|
U.search, U.open && H.value?.scrollIntoActive();
|
|
121
|
-
}), (t,
|
|
140
|
+
}), (t, o) => (b(), h("div", {
|
|
122
141
|
class: "pl-dropdown-multi__envelope",
|
|
123
|
-
onClick:
|
|
142
|
+
onClick: xe,
|
|
124
143
|
"data-testid": "pl-dropdown-multi"
|
|
125
|
-
}, [
|
|
144
|
+
}, [g("div", {
|
|
126
145
|
ref_key: "rootRef",
|
|
127
146
|
ref: B,
|
|
128
|
-
tabindex:
|
|
129
|
-
class:
|
|
147
|
+
tabindex: X.value,
|
|
148
|
+
class: y(["pl-dropdown-multi", {
|
|
130
149
|
open: U.open,
|
|
131
|
-
error:
|
|
150
|
+
error: v.error,
|
|
132
151
|
disabled: Y.value
|
|
133
152
|
}]),
|
|
134
153
|
"data-testid": "pl-dropdown-multi-control",
|
|
135
|
-
onKeydown:
|
|
154
|
+
onKeydown: Ce,
|
|
136
155
|
onFocusout: $
|
|
137
|
-
}, [
|
|
138
|
-
|
|
139
|
-
|
|
156
|
+
}, [g("div", me, [
|
|
157
|
+
g("div", he, [
|
|
158
|
+
fe(g("input", {
|
|
140
159
|
ref_key: "input",
|
|
141
160
|
ref: V,
|
|
142
|
-
"onUpdate:modelValue":
|
|
161
|
+
"onUpdate:modelValue": o[0] ||= (e) => U.search = e,
|
|
143
162
|
type: "text",
|
|
144
163
|
tabindex: "-1",
|
|
145
164
|
disabled: Y.value,
|
|
146
|
-
placeholder:
|
|
165
|
+
placeholder: ve.value,
|
|
147
166
|
spellcheck: "false",
|
|
148
167
|
autocomplete: "chrome-off",
|
|
149
168
|
"data-testid": "pl-dropdown-multi-input",
|
|
150
|
-
onFocus:
|
|
151
|
-
}, null, 40,
|
|
152
|
-
U.open ?
|
|
169
|
+
onFocus: o[1] ||= (e) => U.open = !0
|
|
170
|
+
}, null, 40, ge), [[le, U.search]]),
|
|
171
|
+
U.open ? m("", !0) : (b(), h("div", k, [(b(!0), h(d, null, S(K.value, (e, t) => (b(), p(E(l), {
|
|
153
172
|
key: t,
|
|
154
|
-
class:
|
|
173
|
+
class: y({ "pl-dropdown-multi__chip--missing": e.isMissing }),
|
|
155
174
|
closeable: "",
|
|
156
175
|
"data-testid": "pl-dropdown-multi-chip",
|
|
157
176
|
small: "",
|
|
158
|
-
onClick:
|
|
159
|
-
onClose: (t) =>
|
|
177
|
+
onClick: o[3] ||= O((e) => U.open = !0, ["stop"]),
|
|
178
|
+
onClose: (t) => Q(e.value)
|
|
160
179
|
}, {
|
|
161
|
-
default:
|
|
180
|
+
default: D(() => [e.hint === void 0 ? (b(), h(d, { key: 1 }, [_(T(e.label), 1)], 64)) : (b(), p(E(n), {
|
|
181
|
+
key: 0,
|
|
182
|
+
element: "span",
|
|
183
|
+
position: "top",
|
|
184
|
+
"data-testid": "pl-dropdown-multi-chip-hint",
|
|
185
|
+
onMouseover: o[2] ||= O(() => {}, ["stop"])
|
|
186
|
+
}, {
|
|
187
|
+
tooltip: D(() => [(b(), p(w(e.hint)))]),
|
|
188
|
+
default: D(() => [g("span", null, T(e.label), 1)]),
|
|
189
|
+
_: 2
|
|
190
|
+
}, 1024))]),
|
|
162
191
|
_: 2
|
|
163
192
|
}, 1032, ["class", "onClose"]))), 128))])),
|
|
164
|
-
|
|
165
|
-
|
|
193
|
+
g("div", A, [
|
|
194
|
+
ye.value ? (b(), p(E(a), {
|
|
166
195
|
key: 0,
|
|
167
196
|
name: "loading",
|
|
168
197
|
"data-testid": "pl-dropdown-multi-loading"
|
|
169
|
-
})) :
|
|
170
|
-
|
|
171
|
-
|
|
198
|
+
})) : m("", !0),
|
|
199
|
+
C(t.$slots, "append"),
|
|
200
|
+
g("div", {
|
|
172
201
|
class: "pl-dropdown-multi__arrow-wrapper",
|
|
173
202
|
"data-testid": "pl-dropdown-multi-arrow",
|
|
174
|
-
onClick:
|
|
175
|
-
}, [...
|
|
203
|
+
onClick: O(Se, ["stop"])
|
|
204
|
+
}, [...o[5] ||= [g("div", { class: "arrow-icon arrow-icon-default" }, null, -1)]])
|
|
176
205
|
])
|
|
177
206
|
]),
|
|
178
|
-
|
|
179
|
-
|
|
207
|
+
v.label ? (b(), h("label", j, [
|
|
208
|
+
v.required ? (b(), p(E(e), {
|
|
180
209
|
key: 0,
|
|
181
|
-
uri:
|
|
210
|
+
uri: E(ne),
|
|
182
211
|
"data-testid": "pl-dropdown-multi-required"
|
|
183
|
-
}, null, 8, ["uri"])) :
|
|
184
|
-
|
|
185
|
-
|
|
212
|
+
}, null, 8, ["uri"])) : m("", !0),
|
|
213
|
+
g("span", null, T(v.label), 1),
|
|
214
|
+
E(_e).tooltip ? (b(), p(E(n), {
|
|
186
215
|
key: 1,
|
|
187
216
|
class: "info",
|
|
188
217
|
position: "top",
|
|
189
218
|
"data-testid": "pl-dropdown-multi-tooltip"
|
|
190
219
|
}, {
|
|
191
|
-
tooltip:
|
|
220
|
+
tooltip: D(() => [C(t.$slots, "tooltip")]),
|
|
192
221
|
_: 3
|
|
193
|
-
})) :
|
|
194
|
-
])) :
|
|
195
|
-
U.open ? (
|
|
222
|
+
})) : m("", !0)
|
|
223
|
+
])) : m("", !0),
|
|
224
|
+
U.open ? (b(), p(te, {
|
|
196
225
|
key: 1,
|
|
197
226
|
ref_key: "overlay",
|
|
198
227
|
ref: H,
|
|
@@ -203,19 +232,29 @@ var ce = ["tabindex"], le = { class: "pl-dropdown-multi__container" }, ue = { cl
|
|
|
203
232
|
tabindex: "-1",
|
|
204
233
|
onFocusout: $
|
|
205
234
|
}, {
|
|
206
|
-
default:
|
|
207
|
-
|
|
235
|
+
default: D(() => [
|
|
236
|
+
g("div", M, [(b(!0), h(d, null, S(K.value, (e, t) => (b(), p(E(l), {
|
|
208
237
|
key: t,
|
|
209
|
-
class:
|
|
238
|
+
class: y({ "pl-dropdown-multi__chip--missing": e.isMissing }),
|
|
210
239
|
closeable: "",
|
|
211
240
|
"data-testid": "pl-dropdown-multi-chip",
|
|
212
241
|
small: "",
|
|
213
|
-
onClose: (t) =>
|
|
242
|
+
onClose: (t) => Q(e.value)
|
|
214
243
|
}, {
|
|
215
|
-
default:
|
|
244
|
+
default: D(() => [e.hint === void 0 ? (b(), h(d, { key: 1 }, [_(T(e.label), 1)], 64)) : (b(), p(E(n), {
|
|
245
|
+
key: 0,
|
|
246
|
+
element: "span",
|
|
247
|
+
position: "top",
|
|
248
|
+
"data-testid": "pl-dropdown-multi-chip-hint",
|
|
249
|
+
onMouseover: o[4] ||= O(() => {}, ["stop"])
|
|
250
|
+
}, {
|
|
251
|
+
tooltip: D(() => [(b(), p(w(e.hint)))]),
|
|
252
|
+
default: D(() => [g("span", null, T(e.label), 1)]),
|
|
253
|
+
_: 2
|
|
254
|
+
}, 1024))]),
|
|
216
255
|
_: 2
|
|
217
256
|
}, 1032, ["class", "onClose"]))), 128))]),
|
|
218
|
-
(
|
|
257
|
+
(b(!0), h(d, null, S(q.value, (e, t) => (b(), p(r, {
|
|
219
258
|
key: t,
|
|
220
259
|
option: e,
|
|
221
260
|
"text-item": "text",
|
|
@@ -224,24 +263,24 @@ var ce = ["tabindex"], le = { class: "pl-dropdown-multi__container" }, ue = { cl
|
|
|
224
263
|
size: "medium",
|
|
225
264
|
"use-checkbox": "",
|
|
226
265
|
"data-testid": "pl-dropdown-multi-option",
|
|
227
|
-
onClick:
|
|
266
|
+
onClick: O((t) => Z(e.value), ["stop"])
|
|
228
267
|
}, null, 8, [
|
|
229
268
|
"option",
|
|
230
269
|
"is-selected",
|
|
231
270
|
"is-hovered",
|
|
232
271
|
"onClick"
|
|
233
272
|
]))), 128)),
|
|
234
|
-
q.value.length ?
|
|
273
|
+
q.value.length ? m("", !0) : (b(), h("div", N, " Nothing found "))
|
|
235
274
|
]),
|
|
236
275
|
_: 1
|
|
237
|
-
}, 8, ["root"])) :
|
|
238
|
-
|
|
276
|
+
}, 8, ["root"])) : m("", !0),
|
|
277
|
+
ae(ee, {
|
|
239
278
|
class: "pl-dropdown-multi__contour",
|
|
240
|
-
"group-position":
|
|
279
|
+
"group-position": v.groupPosition
|
|
241
280
|
}, null, 8, ["group-position"])
|
|
242
|
-
])], 42,
|
|
281
|
+
])], 42, pe), v.error ? (b(), h("div", P, T(E(i)(v.error)), 1)) : v.helper ? (b(), h("div", F, T(v.helper), 1)) : m("", !0)]));
|
|
243
282
|
}
|
|
244
283
|
});
|
|
245
|
-
export {
|
|
284
|
+
export { I as default };
|
|
246
285
|
|
|
247
286
|
//# sourceMappingURL=PlDropdownMulti.vue2.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlDropdownMulti.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createElementBlock","_createElementVNode","_normalizeClass","_withDirectives","_vModelText","_Fragment","_renderList","_createBlock","_unref","PlChip","_withModifiers","_withCtx","_createTextVNode","_toDisplayString","_createCommentVNode","PlIcon24","_renderSlot","PlSvg","SvgRequired","PlTooltip","DropdownOverlay","DropdownListItem","_createVNode","DoubleContour","PlSvg_default","PlTooltip_default","DropdownListItem_default","PlIcon24_default","DoubleContour_default","DropdownOverlay_default","required_default","PlChip_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","PlDropdownMulti_vue_vue_type_script_setup_true_lang_default","__emit","emit","emitModel","v","slots","useSlots","props","__props","rootRef","ref","input","overlay","useTemplateRef","data","reactive","selectedValuesRef","computed","placeholderRef","normalizedOptionsRef","normalizeListOptions","selectedOptionsRef","optionsLoaded","opt","deepEqual","o","filteredOptionsRef","selectedValues","unref","options","search","deepIncludes","isLoadingOptions","showLoadingSpinner","isDisabled","tabindex","updateActiveOption","selectOption","values","it","unselectOption","d","setFocusOnInput","toggleModel","onFocusOut","relatedTarget","event","handleKeydown","open","filteredOptions","length","activeOption","useLabelNotch","watch","watchPostEffect","openBlock","createElementBlock","createElementVNode","normalizeClass","withDirectives","_cache","$event","vModelText","createCommentVNode","Fragment","renderList","createBlock","i","withModifiers","withCtx","createTextVNode","toDisplayString","renderSlot","_ctx","index","item","createVNode","getErrorMessage"],"sources":["../../../src/components/PlDropdownMulti/PlDropdownMulti.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * A component for selecting multiple values from a list of options\n */\nexport default {\n name: \"PlDropdownMulti\",\n};\n</script>\n\n<script lang=\"ts\" setup generic=\"M = unknown\">\nimport {\n computed,\n reactive,\n ref,\n unref,\n useSlots,\n useTemplateRef,\n watch,\n watchPostEffect,\n} from \"vue\";\nimport SvgRequired from \"../../assets/images/required.svg?raw\";\nimport { getErrorMessage } from \"../../helpers/error.ts\";\nimport { deepEqual, deepIncludes } from \"../../helpers/objects\";\nimport { normalizeListOptions } from \"../../helpers/utils\";\nimport type { ListOption } from \"../../types\";\nimport DoubleContour from \"../../utils/DoubleContour.vue\";\nimport DropdownOverlay from \"../../utils/DropdownOverlay/DropdownOverlay.vue\";\nimport { useLabelNotch } from \"../../utils/useLabelNotch\";\nimport DropdownListItem from \"../DropdownListItem.vue\";\nimport { PlChip } from \"../PlChip\";\nimport { PlIcon24 } from \"../PlIcon24\";\nimport { PlSvg } from \"../PlSvg\";\nimport { PlTooltip } from \"../PlTooltip\";\nimport \"./pl-dropdown-multi.scss\";\n\nconst emit = defineEmits<{\n (e: \"update:modelValue\", v: M[]): void;\n}>();\n\nconst emitModel = (v: M[]) => emit(\"update:modelValue\", v);\n\nconst slots = useSlots();\n\nconst props = withDefaults(\n defineProps<{\n /**\n * The current selected values.\n */\n modelValue: M[];\n /**\n * The label text for the dropdown field (optional)\n */\n label?: string;\n /**\n * List of available options for the dropdown\n */\n options?: Readonly<ListOption<M>[]>;\n /**\n * A helper text displayed below the dropdown when there are no errors (optional).\n */\n helper?: string;\n /**\n * Error message displayed below the dropdown (optional)\n */\n error?: unknown;\n /**\n * Placeholder text shown when no value is selected.\n */\n placeholder?: string;\n /**\n * Text shown in a chip when a `modelValue` entry is missing from `options` —\n * e.g. its upstream source was deleted. Rendered italic in error color.\n */\n missingValueLabel?: string;\n /**\n * If `true`, the dropdown component is marked as required.\n */\n required?: boolean;\n /**\n * If `true`, the dropdown component is disabled and cannot be interacted with.\n */\n disabled?: boolean;\n /**\n * Makes some of corners not rounded\n * */\n groupPosition?:\n | \"top\"\n | \"bottom\"\n | \"left\"\n | \"right\"\n | \"top-left\"\n | \"top-right\"\n | \"bottom-left\"\n | \"bottom-right\"\n | \"middle\";\n }>(),\n {\n modelValue: () => [],\n label: undefined,\n helper: undefined,\n error: undefined,\n placeholder: \"...\",\n missingValueLabel: \"Value not available\",\n required: false,\n disabled: false,\n options: undefined,\n groupPosition: undefined,\n },\n);\n\nconst rootRef = ref<HTMLElement | undefined>();\nconst input = ref<HTMLInputElement | undefined>();\n\nconst overlay = useTemplateRef(\"overlay\");\n\nconst data = reactive({\n search: \"\",\n activeOption: -1,\n open: false,\n optionsHeight: 0,\n});\n\nconst selectedValuesRef = computed(() => (Array.isArray(props.modelValue) ? props.modelValue : []));\n\nconst placeholderRef = computed(() => {\n if (data.open && props.modelValue.length > 0) {\n return props.placeholder;\n }\n\n return props.modelValue.length > 0 ? \"\" : props.placeholder;\n});\n\nconst normalizedOptionsRef = computed(() => normalizeListOptions(props.options ?? []));\n\nconst selectedOptionsRef = computed(() => {\n // While options load (`options === undefined`), hide chips for unresolved values\n // to avoid a \"missing\" flash that resolves once options arrive.\n const optionsLoaded = props.options !== undefined;\n return selectedValuesRef.value\n .map((v) => {\n const opt = normalizedOptionsRef.value.find((o) => deepEqual(o.value, v));\n if (opt) {\n // Found: render the option's own (normalized) label verbatim — matches\n // PlDropdown. `opt.label` is always a string (possibly \"\"), never an object,\n // so there is no raw-value leak to guard against.\n return { ...opt, isMissing: false };\n }\n if (!optionsLoaded) {\n return undefined;\n }\n // Honor empty `missingValueLabel` verbatim — caller's explicit \"render nothing\".\n return {\n value: v,\n label: props.missingValueLabel,\n isMissing: true,\n };\n })\n .filter((v): v is NonNullable<typeof v> => v !== undefined);\n});\n\nconst filteredOptionsRef = computed(() => {\n const selectedValues = unref(selectedValuesRef);\n\n const options = unref(normalizedOptionsRef);\n\n return (\n data.search\n ? options.filter((opt) => {\n const search = data.search.toLowerCase();\n\n if (opt.label.toLowerCase().includes(search)) {\n return true;\n }\n\n if (typeof opt.value === \"string\") {\n return opt.value.toLowerCase().includes(search);\n }\n\n return opt.value === data.search;\n })\n : [...options]\n ).map((opt) => ({\n ...opt,\n selected: deepIncludes(selectedValues, opt.value),\n }));\n});\n\nconst isLoadingOptions = computed(() => {\n return props.options === undefined;\n});\n\nconst showLoadingSpinner = computed(() => {\n return !props.disabled && isLoadingOptions.value;\n});\n\nconst isDisabled = computed(() => {\n if (isLoadingOptions.value) {\n return true;\n }\n\n return props.disabled;\n});\n\nconst tabindex = computed(() => (isDisabled.value ? undefined : \"0\"));\n\nconst updateActiveOption = () => {\n data.activeOption = 0;\n};\n\nconst selectOption = (v: M) => {\n const values = unref(selectedValuesRef);\n emitModel(deepIncludes(values, v) ? values.filter((it) => !deepEqual(it, v)) : [...values, v]);\n data.search = \"\";\n rootRef?.value?.focus();\n};\n\nconst unselectOption = (d: M) =>\n emitModel(unref(selectedValuesRef).filter((v) => !deepEqual(v, d)));\n\nconst setFocusOnInput = () => input.value?.focus();\n\nconst toggleModel = () => {\n data.open = !data.open;\n if (!data.open) {\n data.search = \"\";\n }\n};\n\nconst onFocusOut = (event: FocusEvent) => {\n const relatedTarget = event.relatedTarget as Node | null;\n\n if (!rootRef.value?.contains(relatedTarget) && !overlay.value?.listRef?.contains(relatedTarget)) {\n data.search = \"\";\n data.open = false;\n }\n};\n\nconst handleKeydown = (e: { code: string; preventDefault(): void }) => {\n const { open, activeOption } = data;\n\n if (!open) {\n if (e.code === \"Enter\") {\n data.open = true;\n }\n return;\n }\n\n if (e.code === \"Escape\") {\n data.open = false;\n rootRef.value?.focus();\n }\n\n const filteredOptions = unref(filteredOptionsRef);\n\n const { length } = filteredOptions;\n\n if (!length) {\n return;\n }\n\n if ([\"ArrowDown\", \"ArrowUp\", \"Enter\"].includes(e.code)) {\n e.preventDefault();\n }\n\n if (e.code === \"Enter\") {\n selectOption(filteredOptions[activeOption].value);\n }\n\n const d = e.code === \"ArrowDown\" ? 1 : e.code === \"ArrowUp\" ? -1 : 0;\n\n data.activeOption = Math.abs(activeOption + d + length) % length;\n\n requestAnimationFrame(() => overlay.value?.scrollIntoActive());\n};\n\nuseLabelNotch(rootRef);\n\nwatch(\n () => props.modelValue,\n () => updateActiveOption(),\n { immediate: true },\n);\n\nwatchPostEffect(() => {\n // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n data.search;\n\n if (data.open) {\n overlay.value?.scrollIntoActive();\n }\n});\n</script>\n\n<template>\n <div class=\"pl-dropdown-multi__envelope\" @click=\"setFocusOnInput\" data-testid=\"pl-dropdown-multi\">\n <div\n ref=\"rootRef\"\n :tabindex=\"tabindex\"\n class=\"pl-dropdown-multi\"\n data-testid=\"pl-dropdown-multi-control\"\n :class=\"{ open: data.open, error, disabled: isDisabled }\"\n @keydown=\"handleKeydown\"\n @focusout=\"onFocusOut\"\n >\n <div class=\"pl-dropdown-multi__container\">\n <div class=\"pl-dropdown-multi__field\">\n <input\n ref=\"input\"\n v-model=\"data.search\"\n type=\"text\"\n tabindex=\"-1\"\n :disabled=\"isDisabled\"\n :placeholder=\"placeholderRef\"\n spellcheck=\"false\"\n autocomplete=\"chrome-off\"\n data-testid=\"pl-dropdown-multi-input\"\n @focus=\"data.open = true\"\n />\n <div v-if=\"!data.open\" class=\"chips-container\" data-testid=\"pl-dropdown-multi-chips\">\n <PlChip\n v-for=\"(opt, i) in selectedOptionsRef\"\n :key=\"i\"\n :class=\"{ 'pl-dropdown-multi__chip--missing': opt.isMissing }\"\n closeable\n data-testid=\"pl-dropdown-multi-chip\"\n small\n @click.stop=\"data.open = true\"\n @close=\"unselectOption(opt.value)\"\n >\n {{ opt.label }}\n </PlChip>\n </div>\n\n <div class=\"pl-dropdown-multi__controls\">\n <PlIcon24\n v-if=\"showLoadingSpinner\"\n name=\"loading\"\n data-testid=\"pl-dropdown-multi-loading\"\n />\n <slot name=\"append\" />\n <div\n class=\"pl-dropdown-multi__arrow-wrapper\"\n data-testid=\"pl-dropdown-multi-arrow\"\n @click.stop=\"toggleModel\"\n >\n <div class=\"arrow-icon arrow-icon-default\" />\n </div>\n </div>\n </div>\n <label v-if=\"label\" data-testid=\"pl-dropdown-multi-label\">\n <PlSvg v-if=\"required\" :uri=\"SvgRequired\" data-testid=\"pl-dropdown-multi-required\" />\n <span>{{ label }}</span>\n <PlTooltip\n v-if=\"slots.tooltip\"\n class=\"info\"\n position=\"top\"\n data-testid=\"pl-dropdown-multi-tooltip\"\n >\n <template #tooltip>\n <slot name=\"tooltip\" />\n </template>\n </PlTooltip>\n </label>\n <DropdownOverlay\n v-if=\"data.open\"\n ref=\"overlay\"\n :root=\"rootRef\"\n class=\"pl-dropdown-multi__options\"\n data-testid=\"pl-dropdown-multi-options\"\n :gap=\"5\"\n tabindex=\"-1\"\n @focusout=\"onFocusOut\"\n >\n <div\n class=\"pl-dropdown-multi__open-chips-container\"\n data-testid=\"pl-dropdown-multi-chips\"\n >\n <PlChip\n v-for=\"(opt, i) in selectedOptionsRef\"\n :key=\"i\"\n :class=\"{ 'pl-dropdown-multi__chip--missing': opt.isMissing }\"\n closeable\n data-testid=\"pl-dropdown-multi-chip\"\n small\n @close=\"unselectOption(opt.value)\"\n >\n {{ opt.label }}\n </PlChip>\n </div>\n <DropdownListItem\n v-for=\"(item, index) in filteredOptionsRef\"\n :key=\"index\"\n :option=\"item\"\n :text-item=\"'text'\"\n :is-selected=\"item.selected\"\n :is-hovered=\"data.activeOption == index\"\n size=\"medium\"\n use-checkbox\n data-testid=\"pl-dropdown-multi-option\"\n @click.stop=\"selectOption(item.value)\"\n />\n <div\n v-if=\"!filteredOptionsRef.length\"\n class=\"nothing-found\"\n data-testid=\"pl-dropdown-multi-options-empty\"\n >\n Nothing found\n </div>\n </DropdownOverlay>\n <DoubleContour class=\"pl-dropdown-multi__contour\" :group-position=\"groupPosition\" />\n </div>\n </div>\n <div v-if=\"error\" class=\"pl-dropdown-multi__error\" data-testid=\"pl-dropdown-multi-error\">\n {{ getErrorMessage(error) }}\n </div>\n <div\n v-else-if=\"helper\"\n class=\"pl-dropdown-multi__helper\"\n data-testid=\"pl-dropdown-multi-helper\"\n >\n {{ helper }}\n </div>\n </div>\n</template>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PlDropdownMulti.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createElementBlock","_createElementVNode","_normalizeClass","_withDirectives","_vModelText","_Fragment","_renderList","_createBlock","_unref","PlChip","_withModifiers","_withCtx","PlTooltip","_resolveDynamicComponent","_toDisplayString","_createTextVNode","_createCommentVNode","PlIcon24","_renderSlot","PlSvg","SvgRequired","DropdownOverlay","DropdownListItem","_createVNode","DoubleContour","PlSvg_default","PlTooltip_default","DropdownListItem_default","PlIcon24_default","DoubleContour_default","DropdownOverlay_default","required_default","PlChip_default","_hoisted_1","_hoisted_2","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_hoisted_11","PlDropdownMulti_vue_vue_type_script_setup_true_lang_default","__emit","emit","emitModel","v","slots","useSlots","props","__props","rootRef","ref","input","overlay","useTemplateRef","data","reactive","selectedValuesRef","computed","placeholderRef","normalizedOptionsRef","normalizeListOptions","selectedOptionsRef","optionsLoaded","opt","deepEqual","o","label","pickedValueText","missingValueText","missingValueTooltip","filteredOptionsRef","selectedValues","unref","options","search","deepIncludes","isLoadingOptions","showLoadingSpinner","isDisabled","tabindex","updateActiveOption","selectOption","values","it","unselectOption","d","setFocusOnInput","toggleModel","onFocusOut","relatedTarget","event","handleKeydown","open","filteredOptions","length","activeOption","useLabelNotch","watch","watchPostEffect","openBlock","createElementBlock","createElementVNode","normalizeClass","withDirectives","_cache","$event","vModelText","createCommentVNode","Fragment","renderList","createBlock","i","withModifiers","withCtx","createTextVNode","toDisplayString","resolveDynamicComponent","renderSlot","_ctx","index","item","createVNode","getErrorMessage"],"sources":["../../../src/components/PlDropdownMulti/PlDropdownMulti.vue"],"sourcesContent":["<script lang=\"ts\">\n/**\n * A component for selecting multiple values from a list of options\n */\nexport default {\n name: \"PlDropdownMulti\",\n};\n</script>\n\n<script lang=\"ts\" setup generic=\"M = unknown\">\nimport {\n computed,\n reactive,\n ref,\n unref,\n useSlots,\n useTemplateRef,\n watch,\n watchPostEffect,\n} from \"vue\";\nimport SvgRequired from \"../../assets/images/required.svg?raw\";\nimport { missingValueText, missingValueTooltip, pickedValueText } from \"../../helpers/columnValue\";\nimport type { MissingValueLabel, MissingValueTooltip } from \"../../helpers/columnValue\";\nimport { getErrorMessage } from \"../../helpers/error.ts\";\nimport { deepEqual, deepIncludes } from \"../../helpers/objects\";\nimport { normalizeListOptions } from \"../../helpers/utils\";\nimport type { ListOption } from \"../../types\";\nimport DoubleContour from \"../../utils/DoubleContour.vue\";\nimport DropdownOverlay from \"../../utils/DropdownOverlay/DropdownOverlay.vue\";\nimport { useLabelNotch } from \"../../utils/useLabelNotch\";\nimport DropdownListItem from \"../DropdownListItem.vue\";\nimport { PlChip } from \"../PlChip\";\nimport { PlIcon24 } from \"../PlIcon24\";\nimport { PlSvg } from \"../PlSvg\";\nimport { PlTooltip } from \"../PlTooltip\";\nimport \"./pl-dropdown-multi.scss\";\n\nconst emit = defineEmits<{\n (e: \"update:modelValue\", v: M[]): void;\n}>();\n\nconst emitModel = (v: M[]) => emit(\"update:modelValue\", v);\n\nconst slots = useSlots();\n\nconst props = withDefaults(\n defineProps<{\n /**\n * The current selected values.\n */\n modelValue: M[];\n /**\n * The label text for the dropdown field (optional)\n */\n label?: string;\n /**\n * List of available options for the dropdown\n */\n options?: Readonly<ListOption<M>[]>;\n /**\n * A helper text displayed below the dropdown when there are no errors (optional).\n */\n helper?: string;\n /**\n * Error message displayed below the dropdown (optional)\n */\n error?: unknown;\n /**\n * Placeholder text shown when no value is selected.\n */\n placeholder?: string;\n /**\n * Text shown in a chip when a `modelValue` entry is missing from `options` —\n * e.g. its upstream source was deleted. Rendered italic in error color. One text for every\n * such value, or a function giving it per value. By default, the value a column value id\n * picks, marked as not available, or \"Value not available\".\n */\n missingValueLabel?: MissingValueLabel;\n /**\n * Explains a selected value missing from the options in a tooltip over it: one text for every\n * such value, or a function giving the content per value.\n */\n missingValueTooltip?: MissingValueTooltip;\n /**\n * If `true`, the dropdown component is marked as required.\n */\n required?: boolean;\n /**\n * If `true`, the dropdown component is disabled and cannot be interacted with.\n */\n disabled?: boolean;\n /**\n * Makes some of corners not rounded\n * */\n groupPosition?:\n | \"top\"\n | \"bottom\"\n | \"left\"\n | \"right\"\n | \"top-left\"\n | \"top-right\"\n | \"bottom-left\"\n | \"bottom-right\"\n | \"middle\";\n }>(),\n {\n modelValue: () => [],\n label: undefined,\n helper: undefined,\n error: undefined,\n placeholder: \"...\",\n missingValueLabel: undefined,\n missingValueTooltip: undefined,\n required: false,\n disabled: false,\n options: undefined,\n groupPosition: undefined,\n },\n);\n\nconst rootRef = ref<HTMLElement | undefined>();\nconst input = ref<HTMLInputElement | undefined>();\n\nconst overlay = useTemplateRef(\"overlay\");\n\nconst data = reactive({\n search: \"\",\n activeOption: -1,\n open: false,\n optionsHeight: 0,\n});\n\nconst selectedValuesRef = computed(() => (Array.isArray(props.modelValue) ? props.modelValue : []));\n\nconst placeholderRef = computed(() => {\n if (data.open && props.modelValue.length > 0) {\n return props.placeholder;\n }\n\n return props.modelValue.length > 0 ? \"\" : props.placeholder;\n});\n\nconst normalizedOptionsRef = computed(() => normalizeListOptions(props.options ?? []));\n\nconst selectedOptionsRef = computed(() => {\n // While options load (`options === undefined`), hide chips for unresolved values\n // to avoid a \"missing\" flash that resolves once options arrive. A picked column value\n // is shown by its own label meanwhile.\n const optionsLoaded = props.options !== undefined;\n return selectedValuesRef.value\n .map((v) => {\n const opt = normalizedOptionsRef.value.find((o) => deepEqual(o.value, v));\n if (opt) {\n // Found: render the option's own (normalized) label verbatim — matches\n // PlDropdown. `opt.label` is always a string (possibly \"\"), never an object,\n // so there is no raw-value leak to guard against.\n return { ...opt, isMissing: false, hint: undefined };\n }\n if (!optionsLoaded) {\n const label = pickedValueText(v);\n return label === undefined\n ? undefined\n : { value: v, label, isMissing: false, hint: undefined };\n }\n // Honor empty `missingValueLabel` verbatim — caller's explicit \"render nothing\".\n return {\n value: v,\n label: missingValueText(v, props.missingValueLabel),\n isMissing: true,\n hint: missingValueTooltip(v, props.missingValueTooltip),\n };\n })\n .filter((v): v is NonNullable<typeof v> => v !== undefined);\n});\n\nconst filteredOptionsRef = computed(() => {\n const selectedValues = unref(selectedValuesRef);\n\n const options = unref(normalizedOptionsRef);\n\n return (\n data.search\n ? options.filter((opt) => {\n const search = data.search.toLowerCase();\n\n if (opt.label.toLowerCase().includes(search)) {\n return true;\n }\n\n if (typeof opt.value === \"string\") {\n return opt.value.toLowerCase().includes(search);\n }\n\n return opt.value === data.search;\n })\n : [...options]\n ).map((opt) => ({\n ...opt,\n selected: deepIncludes(selectedValues, opt.value),\n }));\n});\n\nconst isLoadingOptions = computed(() => {\n return props.options === undefined;\n});\n\nconst showLoadingSpinner = computed(() => {\n return !props.disabled && isLoadingOptions.value;\n});\n\nconst isDisabled = computed(() => {\n if (isLoadingOptions.value) {\n return true;\n }\n\n return props.disabled;\n});\n\nconst tabindex = computed(() => (isDisabled.value ? undefined : \"0\"));\n\nconst updateActiveOption = () => {\n data.activeOption = 0;\n};\n\nconst selectOption = (v: M) => {\n const values = unref(selectedValuesRef);\n emitModel(deepIncludes(values, v) ? values.filter((it) => !deepEqual(it, v)) : [...values, v]);\n data.search = \"\";\n rootRef?.value?.focus();\n};\n\nconst unselectOption = (d: M) =>\n emitModel(unref(selectedValuesRef).filter((v) => !deepEqual(v, d)));\n\nconst setFocusOnInput = () => input.value?.focus();\n\nconst toggleModel = () => {\n data.open = !data.open;\n if (!data.open) {\n data.search = \"\";\n }\n};\n\nconst onFocusOut = (event: FocusEvent) => {\n const relatedTarget = event.relatedTarget as Node | null;\n\n if (!rootRef.value?.contains(relatedTarget) && !overlay.value?.listRef?.contains(relatedTarget)) {\n data.search = \"\";\n data.open = false;\n }\n};\n\nconst handleKeydown = (e: { code: string; preventDefault(): void }) => {\n const { open, activeOption } = data;\n\n if (!open) {\n if (e.code === \"Enter\") {\n data.open = true;\n }\n return;\n }\n\n if (e.code === \"Escape\") {\n data.open = false;\n rootRef.value?.focus();\n }\n\n const filteredOptions = unref(filteredOptionsRef);\n\n const { length } = filteredOptions;\n\n if (!length) {\n return;\n }\n\n if ([\"ArrowDown\", \"ArrowUp\", \"Enter\"].includes(e.code)) {\n e.preventDefault();\n }\n\n if (e.code === \"Enter\") {\n selectOption(filteredOptions[activeOption].value);\n }\n\n const d = e.code === \"ArrowDown\" ? 1 : e.code === \"ArrowUp\" ? -1 : 0;\n\n data.activeOption = Math.abs(activeOption + d + length) % length;\n\n requestAnimationFrame(() => overlay.value?.scrollIntoActive());\n};\n\nuseLabelNotch(rootRef);\n\nwatch(\n () => props.modelValue,\n () => updateActiveOption(),\n { immediate: true },\n);\n\nwatchPostEffect(() => {\n // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n data.search;\n\n if (data.open) {\n overlay.value?.scrollIntoActive();\n }\n});\n</script>\n\n<template>\n <div class=\"pl-dropdown-multi__envelope\" @click=\"setFocusOnInput\" data-testid=\"pl-dropdown-multi\">\n <div\n ref=\"rootRef\"\n :tabindex=\"tabindex\"\n class=\"pl-dropdown-multi\"\n data-testid=\"pl-dropdown-multi-control\"\n :class=\"{ open: data.open, error, disabled: isDisabled }\"\n @keydown=\"handleKeydown\"\n @focusout=\"onFocusOut\"\n >\n <div class=\"pl-dropdown-multi__container\">\n <div class=\"pl-dropdown-multi__field\">\n <input\n ref=\"input\"\n v-model=\"data.search\"\n type=\"text\"\n tabindex=\"-1\"\n :disabled=\"isDisabled\"\n :placeholder=\"placeholderRef\"\n spellcheck=\"false\"\n autocomplete=\"chrome-off\"\n data-testid=\"pl-dropdown-multi-input\"\n @focus=\"data.open = true\"\n />\n <div v-if=\"!data.open\" class=\"chips-container\" data-testid=\"pl-dropdown-multi-chips\">\n <PlChip\n v-for=\"(opt, i) in selectedOptionsRef\"\n :key=\"i\"\n :class=\"{ 'pl-dropdown-multi__chip--missing': opt.isMissing }\"\n closeable\n data-testid=\"pl-dropdown-multi-chip\"\n small\n @click.stop=\"data.open = true\"\n @close=\"unselectOption(opt.value)\"\n >\n <!-- The hover stops here: the tooltip of the chip itself would close this one. -->\n <PlTooltip\n v-if=\"opt.hint !== undefined\"\n element=\"span\"\n position=\"top\"\n data-testid=\"pl-dropdown-multi-chip-hint\"\n @mouseover.stop\n >\n <span>{{ opt.label }}</span>\n <template #tooltip>\n <component :is=\"opt.hint\" />\n </template>\n </PlTooltip>\n <template v-else>{{ opt.label }}</template>\n </PlChip>\n </div>\n\n <div class=\"pl-dropdown-multi__controls\">\n <PlIcon24\n v-if=\"showLoadingSpinner\"\n name=\"loading\"\n data-testid=\"pl-dropdown-multi-loading\"\n />\n <slot name=\"append\" />\n <div\n class=\"pl-dropdown-multi__arrow-wrapper\"\n data-testid=\"pl-dropdown-multi-arrow\"\n @click.stop=\"toggleModel\"\n >\n <div class=\"arrow-icon arrow-icon-default\" />\n </div>\n </div>\n </div>\n <label v-if=\"label\" data-testid=\"pl-dropdown-multi-label\">\n <PlSvg v-if=\"required\" :uri=\"SvgRequired\" data-testid=\"pl-dropdown-multi-required\" />\n <span>{{ label }}</span>\n <PlTooltip\n v-if=\"slots.tooltip\"\n class=\"info\"\n position=\"top\"\n data-testid=\"pl-dropdown-multi-tooltip\"\n >\n <template #tooltip>\n <slot name=\"tooltip\" />\n </template>\n </PlTooltip>\n </label>\n <DropdownOverlay\n v-if=\"data.open\"\n ref=\"overlay\"\n :root=\"rootRef\"\n class=\"pl-dropdown-multi__options\"\n data-testid=\"pl-dropdown-multi-options\"\n :gap=\"5\"\n tabindex=\"-1\"\n @focusout=\"onFocusOut\"\n >\n <div\n class=\"pl-dropdown-multi__open-chips-container\"\n data-testid=\"pl-dropdown-multi-chips\"\n >\n <PlChip\n v-for=\"(opt, i) in selectedOptionsRef\"\n :key=\"i\"\n :class=\"{ 'pl-dropdown-multi__chip--missing': opt.isMissing }\"\n closeable\n data-testid=\"pl-dropdown-multi-chip\"\n small\n @close=\"unselectOption(opt.value)\"\n >\n <!-- The hover stops here: the tooltip of the chip itself would close this one. -->\n <PlTooltip\n v-if=\"opt.hint !== undefined\"\n element=\"span\"\n position=\"top\"\n data-testid=\"pl-dropdown-multi-chip-hint\"\n @mouseover.stop\n >\n <span>{{ opt.label }}</span>\n <template #tooltip>\n <component :is=\"opt.hint\" />\n </template>\n </PlTooltip>\n <template v-else>{{ opt.label }}</template>\n </PlChip>\n </div>\n <DropdownListItem\n v-for=\"(item, index) in filteredOptionsRef\"\n :key=\"index\"\n :option=\"item\"\n :text-item=\"'text'\"\n :is-selected=\"item.selected\"\n :is-hovered=\"data.activeOption == index\"\n size=\"medium\"\n use-checkbox\n data-testid=\"pl-dropdown-multi-option\"\n @click.stop=\"selectOption(item.value)\"\n />\n <div\n v-if=\"!filteredOptionsRef.length\"\n class=\"nothing-found\"\n data-testid=\"pl-dropdown-multi-options-empty\"\n >\n Nothing found\n </div>\n </DropdownOverlay>\n <DoubleContour class=\"pl-dropdown-multi__contour\" :group-position=\"groupPosition\" />\n </div>\n </div>\n <div v-if=\"error\" class=\"pl-dropdown-multi__error\" data-testid=\"pl-dropdown-multi-error\">\n {{ getErrorMessage(error) }}\n </div>\n <div\n v-else-if=\"helper\"\n class=\"pl-dropdown-multi__helper\"\n data-testid=\"pl-dropdown-multi-helper\"\n >\n {{ helper }}\n </div>\n </div>\n</template>\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PlDropdownMultiRef.js","names":["_sfc_main","PlDropdownMultiRef_vue_vue_type_script_setup_true_lang_default","PlDropdownMultiRef_default"],"sources":["../../../src/components/PlDropdownMultiRef/PlDropdownMultiRef.vue"],"sourcesContent":["<script lang=\"ts\" setup>\nimport type { ModelRef, RefOption } from \"../../types\";\nimport PlDropdownMulti from \"../PlDropdownMulti/PlDropdownMulti.vue\";\nimport { computed, useSlots } from \"vue\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst slots: any = useSlots();\n\ndefineEmits<{\n /**\n * Emitted when the model value is updated.\n */\n (e: \"update:modelValue\", value: ModelRef[] | undefined): void;\n}>();\n\nconst props = withDefaults(\n defineProps<{\n /**\n * The current selected values.\n */\n modelValue: ModelRef[] | undefined;\n /**\n * The label text for the dropdown field (optional)\n */\n label?: string;\n /**\n * List of available options for the dropdown\n */\n options?: Readonly<RefOption[]>;\n /**\n * A helper text displayed below the dropdown when there are no errors (optional).\n */\n helper?: string;\n /**\n * Error message displayed below the dropdown (optional)\n */\n error?: unknown;\n /**\n * Placeholder text shown when no value is selected.\n */\n placeholder?: string;\n /**\n * Text shown in a chip when a `modelValue` entry's upstream block no longer\n * exists. Defaults to \"
|
|
1
|
+
{"version":3,"file":"PlDropdownMultiRef.js","names":["_sfc_main","PlDropdownMultiRef_vue_vue_type_script_setup_true_lang_default","PlDropdownMultiRef_default"],"sources":["../../../src/components/PlDropdownMultiRef/PlDropdownMultiRef.vue"],"sourcesContent":["<script lang=\"ts\" setup>\nimport type { MissingValueLabel, MissingValueTooltip } from \"../../helpers/columnValue\";\nimport type { ModelRef, RefOption } from \"../../types\";\nimport PlDropdownMulti from \"../PlDropdownMulti/PlDropdownMulti.vue\";\nimport { computed, useSlots } from \"vue\";\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst slots: any = useSlots();\n\ndefineEmits<{\n /**\n * Emitted when the model value is updated.\n */\n (e: \"update:modelValue\", value: ModelRef[] | undefined): void;\n}>();\n\nconst props = withDefaults(\n defineProps<{\n /**\n * The current selected values.\n */\n modelValue: ModelRef[] | undefined;\n /**\n * The label text for the dropdown field (optional)\n */\n label?: string;\n /**\n * List of available options for the dropdown\n */\n options?: Readonly<RefOption[]>;\n /**\n * A helper text displayed below the dropdown when there are no errors (optional).\n */\n helper?: string;\n /**\n * Error message displayed below the dropdown (optional)\n */\n error?: unknown;\n /**\n * Placeholder text shown when no value is selected.\n */\n placeholder?: string;\n /**\n * Text shown in a chip when a `modelValue` entry's upstream block no longer\n * exists: one text, or a function giving it per value. Defaults to \"Value not available\".\n */\n missingValueLabel?: MissingValueLabel;\n /**\n * Explains a selected value missing from the options in a tooltip over it: one text for every\n * such value, or a function giving the content per value.\n */\n missingValueTooltip?: MissingValueTooltip;\n /**\n * If `true`, the dropdown component is marked as required.\n */\n required?: boolean;\n /**\n * If `true`, the dropdown component is disabled and cannot be interacted with.\n */\n disabled?: boolean;\n }>(),\n {\n modelValue: () => [],\n label: undefined,\n helper: undefined,\n error: undefined,\n placeholder: \"...\",\n missingValueLabel: undefined,\n missingValueTooltip: undefined,\n required: false,\n disabled: false,\n options: undefined,\n },\n);\n\nconst options = computed(() =>\n props.options?.map((opt) => ({\n label: opt.label,\n value: opt.ref,\n })),\n);\n</script>\n\n<template>\n <PlDropdownMulti\n data-testid=\"pl-dropdown-multi-ref\"\n v-bind=\"props\"\n :options=\"options\"\n @update:model-value=\"$emit('update:modelValue', $event)\"\n >\n <template v-if=\"slots.tooltip\" #tooltip>\n <slot name=\"tooltip\" />\n </template>\n </PlDropdownMulti>\n</template>\n"],"mappings":""}
|