admins-components 9.0.78 → 9.0.79
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.
|
@@ -50,7 +50,7 @@ var b = { class: "ac-component" }, x = ["aria-disabled"], ne = {
|
|
|
50
50
|
minWidth: `${e.width}px`,
|
|
51
51
|
maxWidth: `${e.width}px`
|
|
52
52
|
}),
|
|
53
|
-
maxHeight: "
|
|
53
|
+
maxHeight: "20rem"
|
|
54
54
|
});
|
|
55
55
|
function U(e, t) {
|
|
56
56
|
return e == null ? [] : (Array.isArray(e) ? e : [e]).map((e) => e == null ? null : typeof e == "object" && "label" in e ? e : typeof e == "string" ? t.find((t) => t.value === e) ?? {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admins-components26.js","names":[],"sources":["../src/components/DropdownSelect.vue"],"sourcesContent":["<script lang=\"ts\">\nexport interface DropdownSelectConfig {\n placeholder?: string\n filterable?: boolean\n filterPlaceholder?: string\n clearable?: boolean\n textEllipsis?: boolean\n multiple?: boolean\n lazy?: boolean\n size?: ControlSize\n loading?: boolean\n highlight?: boolean\n disabled?: boolean\n}\n\nexport const dropdownSelectConfigDefaults: DropdownSelectConfig = {\n placeholder: 'Válassz...',\n filterable: true,\n filterPlaceholder: 'Kezdj el gépelni...',\n clearable: true,\n textEllipsis: true,\n multiple: false,\n lazy: false,\n loading: false,\n size: 'normal' as ControlSize,\n highlight: true,\n disabled: false,\n}\n\nexport interface DropdownOption {\n icon?: string\n value?: string\n label: string\n callback?: () => void\n}\n\nexport interface DropdownSelectProps {\n modelValue?: DropdownOption | DropdownOption[] | string | string[] | null\n options: DropdownOption[]\n config?: DropdownSelectConfig\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { ref, computed, watch, nextTick } from 'vue'\nimport Button from '@/components/Button.vue'\nimport type { ControlSize } from '@/types/types'\nimport Loader from '@/components/Loader.vue'\nimport { useDropdownAnchor } from '@/composables/useDropdownAnchor'\n\nconst props = withDefaults(defineProps<DropdownSelectProps>(), {\n modelValue: null,\n config: () => ({ ...dropdownSelectConfigDefaults }),\n})\n\nconst cfg = computed(() => ({ ...dropdownSelectConfigDefaults, ...props.config }))\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: DropdownOption | DropdownOption[] | null]\n 'filter-input': [filterText: string]\n}>()\n\nconst filterText = ref('')\nconst wrapperRef = ref<HTMLElement | null>(null)\nconst dropdownRef = ref<HTMLElement | null>(null)\nconst filterInputRef = ref<HTMLInputElement | null>(null)\nconst buffer = ref<DropdownOption[]>([])\nconst selection = ref<DropdownOption[]>(normalizeToOptions(props.modelValue, props.options))\n\nconst { isOpen, dropdownStyle, placement } = useDropdownAnchor(wrapperRef, dropdownRef, {\n extraStyle: (rect) => ({\n minWidth: `${rect.width}px`,\n maxWidth: `${rect.width}px`,\n }),\n maxHeight: '17rem',\n})\n\n\nfunction normalizeToOptions(\n val: DropdownOption | DropdownOption[] | string | string[] | null | undefined,\n options: DropdownOption[],\n): DropdownOption[] {\n if (val == null) return []\n const arr = Array.isArray(val) ? val : [val]\n return arr\n .map((entry): DropdownOption | null => {\n if (entry == null) return null\n if (typeof entry === 'object' && 'label' in entry) {\n return entry as DropdownOption\n }\n if (typeof entry === 'string') {\n const found = options.find((o) => o.value === entry)\n return found ?? { value: entry, label: entry }\n }\n return null\n })\n .filter((o): o is DropdownOption => o !== null)\n}\n\nwatch(\n () => [props.modelValue, props.options],\n ([v]) => {\n selection.value = normalizeToOptions(v as typeof props.modelValue, props.options)\n },\n)\n\nwatch(isOpen, (open) => {\n if (open) {\n filterText.value = ''\n if (cfg.value.filterable) nextTick(() => filterInputRef.value?.focus())\n if (cfg.value.lazy) buffer.value = [...selection.value]\n }\n})\n\nfunction onFilterInput(text: string) {\n filterText.value = text\n emit('filter-input', text)\n}\n\nconst selectedLabel = computed(() => {\n if (selection.value.length === 0) return null\n if (!cfg.value.multiple) {\n const sel = selection.value[0]\n\n return props.options.find((o) => o.value === sel?.value)?.label ?? sel?.label ?? null\n }\n if (selection.value.length > 2) return `${selection.value.length} kiválasztva`\n return selection.value\n .map((sel) => props.options.find((o) => o.value === sel.value)?.label ?? sel.label ?? sel.value)\n .join(', ')\n})\n\nconst filteredOptions = computed(() => {\n const q = filterText.value.toLowerCase()\n return q ? props.options.filter((o) => o.label.toLowerCase().includes(q)) : props.options\n})\n\nfunction escapeHtml(str: string) {\n return str.replace(\n /[&<>\"']/g,\n (m) => ({ '&': '&', '<': '<', '>': '>', '\"': '"', \"'\": ''' })[m]!,\n )\n}\n\nfunction highlight(label: string) {\n const q = filterText.value.trim()\n if (!q || !cfg.value.highlight) return escapeHtml(label)\n\n const safeLabel = escapeHtml(label)\n const safeQ = escapeHtml(q)\n\n const re = new RegExp(safeQ.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'ig')\n return safeLabel.replace(re, (m) => `<mark class=\"ds-option__highlight\">${m}</mark>`)\n}\n\nconst selectableOptions = computed(() => {\n return filteredOptions.value.filter((o) => o.value)\n})\n\nconst allOptionsSelected = computed(() => {\n if (selectableOptions.value.length === 0) return false\n const currentList = cfg.value.lazy && isOpen.value ? buffer.value : selection.value\n return selectableOptions.value.every((o) => o.value && currentList.some((s) => s.value === o.value))\n})\n\nfunction isSelected(value: string): boolean {\n const list = cfg.value.lazy && isOpen.value ? buffer : selection\n return list.value.some((s) => s.value === value)\n}\n\nfunction toggleAllOptions() {\n const currentList = cfg.value.lazy && isOpen.value ? buffer : selection\n const selectableOpts = selectableOptions.value.filter((o) => o.value)\n\n if (allOptionsSelected.value) {\n const selectableValues = new Set(selectableOpts.map((o) => o.value as string))\n currentList.value = currentList.value.filter((s) => !selectableValues.has(s.value ?? ''))\n } else {\n const existingValues = new Set(currentList.value.map((s) => s.value))\n const toAdd = selectableOpts.filter((o) => !existingValues.has(o.value as string))\n currentList.value = [...currentList.value, ...toAdd]\n }\n\n if (!cfg.value.lazy) {\n emit('update:modelValue', selection.value.length > 0 ? [...selection.value] : null)\n }\n}\n\nfunction toggleList(list: DropdownOption[], opt: DropdownOption): DropdownOption[] {\n const idx = list.findIndex((s) => s.value === opt.value)\n return idx >= 0 ? list.filter((_, i) => i !== idx) : [...list, opt]\n}\n\nfunction selectOption(opt: DropdownOption) {\n if (opt.callback) {\n opt.callback()\n isOpen.value = false\n return\n }\n\n const value = opt.value\n if (!value) return\n\n if (cfg.value.multiple) {\n if (cfg.value.lazy) {\n buffer.value = toggleList(buffer.value, opt)\n } else {\n selection.value = toggleList(selection.value, opt)\n emit('update:modelValue', selection.value.length > 0 ? [...selection.value] : null)\n }\n } else {\n selection.value = [opt]\n emit('update:modelValue', opt)\n isOpen.value = false\n }\n}\n\nfunction confirm() {\n if (cfg.value.lazy) {\n selection.value = [...buffer.value]\n emit('update:modelValue', buffer.value.length > 0 ? [...buffer.value] : null)\n }\n isOpen.value = false\n}\n\nfunction clear() {\n if (cfg.value.lazy) {\n buffer.value = []\n } else {\n selection.value = []\n emit('update:modelValue', null)\n }\n}\n\nfunction onOptionKeydown(e: KeyboardEvent, opt: DropdownOption) {\n if (e.key === ' ') {\n e.preventDefault()\n selectOption(opt)\n } else if (e.key === 'Enter') {\n e.preventDefault()\n confirm()\n }\n}\n\nfunction toggleOpen() {\n if (cfg.value.disabled) return\n isOpen.value = !isOpen.value\n if (isOpen.value) {\n if (cfg.value.filterable) {\n filterText.value = ''\n emit('filter-input', '')\n }\n }\n}\n\nfunction clearInput() {\n if (cfg.value.disabled) return\n selection.value = []\n emit('update:modelValue', null)\n isOpen.value = false\n}\n\nfunction focusAndOpen() {\n if (cfg.value.disabled) return\n isOpen.value = true\n if (cfg.value.filterable) nextTick(() => filterInputRef.value?.focus())\n}\n\nfunction handleFilterClear() {\n filterText.value = ''\n emit('filter-input', '')\n}\n\ndefineExpose({ focusAndOpen })\n</script>\n\n<template>\n <div class=\"ac-component\">\n <div ref=\"wrapperRef\" class=\"c-wrapper ds-wrapper\">\n <div\n class=\"c-input-row pointer\"\n :class=\"{\n 'c-input-row--sm': cfg.size === 'small',\n 'c-input-row--lg': cfg.size === 'large',\n 'c-input-row--disabled': cfg.disabled,\n 'c-input-row--open': isOpen,\n }\"\n :aria-disabled=\"cfg.disabled || undefined\"\n @click=\"toggleOpen()\"\n >\n <span v-if=\"selectedLabel\" class=\"c-truncate ds-value\">{{ selectedLabel }}</span>\n <span v-else class=\"c-placeholder\">{{ cfg.placeholder }}</span>\n <button\n v-if=\"cfg.clearable && selection.length > 0\"\n type=\"button\"\n class=\"c-icon-btn c-icon-btn--clear ds-clear-btn\"\n @click.stop=\"clearInput()\"\n aria-label=\"Törlés\"\n >\n <i class=\"fa-solid fa-fw fa-xmark\"></i>\n </button>\n <span\n class=\"c-icon-btn c-icon-btn--chevron mr-2\"\n :class=\"{ 'c-icon-btn--chevron-open': isOpen }\"\n >\n <i class=\"fa-solid fa-fw fa-chevron-down\"></i>\n </span>\n </div>\n </div>\n <Teleport to=\"body\">\n <div class=\"ac-component\">\n <div\n v-if=\"isOpen\"\n ref=\"dropdownRef\"\n class=\"c-dropdown ds-dropdown ds-wrapper\"\n :class=\"{ 'ds-dropdown--multiple': cfg.multiple, 'ds-dropdown--up': placement === 'up' }\"\n :style=\"dropdownStyle\"\n >\n <div v-if=\"cfg.filterable\" class=\"ds-filter\">\n <span\n v-if=\"cfg.multiple\"\n class=\"c-checkbox ds-select-all-checkbox\"\n :class=\"{ 'c-checkbox--checked': allOptionsSelected }\"\n @click.stop=\"toggleAllOptions()\"\n :title=\"allOptionsSelected ? 'Összes kijelölés törlése' : 'Összes kijelölése'\"\n ></span>\n <input\n ref=\"filterInputRef\"\n type=\"text\"\n id=\"ds-filter-input\"\n class=\"c-focus ds-filter-input\"\n :value=\"filterText\"\n @input=\"onFilterInput(($event.target as HTMLInputElement).value)\"\n autocomplete=\"off\"\n :placeholder=\"cfg.filterPlaceholder\"\n @click.stop\n />\n <button\n v-if=\"filterText\"\n type=\"button\"\n class=\"c-icon-btn c-icon-btn--clear ds-filter-clear\"\n @click.stop=\"handleFilterClear()\"\n aria-label=\"Szűrők törlése\"\n >\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n\n <ul class=\"ds-options c-scroll\">\n <li v-if=\"cfg.loading\" class=\"ds-option ds-option--loading\">\n <Loader size=\"2rem\" color=\"var(--neutral-300)\" class=\"m-auto p-3\" />\n </li>\n <template v-else>\n <li\n v-for=\"(opt, idx) in filteredOptions\"\n :key=\"opt.value ?? `cb-${idx}`\"\n class=\"d-option ds-option\"\n :class=\"{ 'ds-option--selected': opt.value && isSelected(opt.value) }\"\n tabindex=\"0\"\n @click=\"selectOption(opt)\"\n @keydown=\"onOptionKeydown($event, opt)\"\n >\n <span\n v-if=\"cfg.multiple && opt.value\"\n class=\"c-checkbox\"\n :class=\"{ 'c-checkbox--checked': isSelected(opt.value) }\"\n ></span>\n <i v-if=\"opt.icon\" class=\"fa-fw\" :class=\"opt.icon\"></i>\n <span\n class=\"d-option__label\"\n :class=\"{ 'c-truncate': cfg.textEllipsis }\"\n v-html=\"highlight(opt.label)\"\n ></span>\n </li>\n <li v-if=\"filteredOptions.length === 0\" class=\"ds-option ds-option--empty\">\n Nincs találat\n </li>\n </template>\n </ul>\n <div v-if=\"cfg.multiple\" class=\"c-footer\">\n <Button v-if=\"cfg.clearable && selection.length > 0\" label=\"Törlés\" outline @click=\"clear\" />\n <Button label=\"OK\" type=\"success\" @click=\"confirm\" />\n </div>\n </div>\n </div>\n </Teleport>\n </div>\n</template>\n\n<style lang=\"scss\" src=\"@/styles/components/dropdown-select.scss\"></style>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"admins-components26.js","names":[],"sources":["../src/components/DropdownSelect.vue"],"sourcesContent":["<script lang=\"ts\">\nexport interface DropdownSelectConfig {\n placeholder?: string\n filterable?: boolean\n filterPlaceholder?: string\n clearable?: boolean\n textEllipsis?: boolean\n multiple?: boolean\n lazy?: boolean\n size?: ControlSize\n loading?: boolean\n highlight?: boolean\n disabled?: boolean\n}\n\nexport const dropdownSelectConfigDefaults: DropdownSelectConfig = {\n placeholder: 'Válassz...',\n filterable: true,\n filterPlaceholder: 'Kezdj el gépelni...',\n clearable: true,\n textEllipsis: true,\n multiple: false,\n lazy: false,\n loading: false,\n size: 'normal' as ControlSize,\n highlight: true,\n disabled: false,\n}\n\nexport interface DropdownOption {\n icon?: string\n value?: string\n label: string\n callback?: () => void\n}\n\nexport interface DropdownSelectProps {\n modelValue?: DropdownOption | DropdownOption[] | string | string[] | null\n options: DropdownOption[]\n config?: DropdownSelectConfig\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { ref, computed, watch, nextTick } from 'vue'\nimport Button from '@/components/Button.vue'\nimport type { ControlSize } from '@/types/types'\nimport Loader from '@/components/Loader.vue'\nimport { useDropdownAnchor } from '@/composables/useDropdownAnchor'\n\nconst props = withDefaults(defineProps<DropdownSelectProps>(), {\n modelValue: null,\n config: () => ({ ...dropdownSelectConfigDefaults }),\n})\n\nconst cfg = computed(() => ({ ...dropdownSelectConfigDefaults, ...props.config }))\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: DropdownOption | DropdownOption[] | null]\n 'filter-input': [filterText: string]\n}>()\n\nconst filterText = ref('')\nconst wrapperRef = ref<HTMLElement | null>(null)\nconst dropdownRef = ref<HTMLElement | null>(null)\nconst filterInputRef = ref<HTMLInputElement | null>(null)\nconst buffer = ref<DropdownOption[]>([])\nconst selection = ref<DropdownOption[]>(normalizeToOptions(props.modelValue, props.options))\n\nconst { isOpen, dropdownStyle, placement } = useDropdownAnchor(wrapperRef, dropdownRef, {\n extraStyle: (rect) => ({\n minWidth: `${rect.width}px`,\n maxWidth: `${rect.width}px`,\n }),\n maxHeight: '20rem',\n})\n\n\nfunction normalizeToOptions(\n val: DropdownOption | DropdownOption[] | string | string[] | null | undefined,\n options: DropdownOption[],\n): DropdownOption[] {\n if (val == null) return []\n const arr = Array.isArray(val) ? val : [val]\n return arr\n .map((entry): DropdownOption | null => {\n if (entry == null) return null\n if (typeof entry === 'object' && 'label' in entry) {\n return entry as DropdownOption\n }\n if (typeof entry === 'string') {\n const found = options.find((o) => o.value === entry)\n return found ?? { value: entry, label: entry }\n }\n return null\n })\n .filter((o): o is DropdownOption => o !== null)\n}\n\nwatch(\n () => [props.modelValue, props.options],\n ([v]) => {\n selection.value = normalizeToOptions(v as typeof props.modelValue, props.options)\n },\n)\n\nwatch(isOpen, (open) => {\n if (open) {\n filterText.value = ''\n if (cfg.value.filterable) nextTick(() => filterInputRef.value?.focus())\n if (cfg.value.lazy) buffer.value = [...selection.value]\n }\n})\n\nfunction onFilterInput(text: string) {\n filterText.value = text\n emit('filter-input', text)\n}\n\nconst selectedLabel = computed(() => {\n if (selection.value.length === 0) return null\n if (!cfg.value.multiple) {\n const sel = selection.value[0]\n\n return props.options.find((o) => o.value === sel?.value)?.label ?? sel?.label ?? null\n }\n if (selection.value.length > 2) return `${selection.value.length} kiválasztva`\n return selection.value\n .map((sel) => props.options.find((o) => o.value === sel.value)?.label ?? sel.label ?? sel.value)\n .join(', ')\n})\n\nconst filteredOptions = computed(() => {\n const q = filterText.value.toLowerCase()\n return q ? props.options.filter((o) => o.label.toLowerCase().includes(q)) : props.options\n})\n\nfunction escapeHtml(str: string) {\n return str.replace(\n /[&<>\"']/g,\n (m) => ({ '&': '&', '<': '<', '>': '>', '\"': '"', \"'\": ''' })[m]!,\n )\n}\n\nfunction highlight(label: string) {\n const q = filterText.value.trim()\n if (!q || !cfg.value.highlight) return escapeHtml(label)\n\n const safeLabel = escapeHtml(label)\n const safeQ = escapeHtml(q)\n\n const re = new RegExp(safeQ.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'ig')\n return safeLabel.replace(re, (m) => `<mark class=\"ds-option__highlight\">${m}</mark>`)\n}\n\nconst selectableOptions = computed(() => {\n return filteredOptions.value.filter((o) => o.value)\n})\n\nconst allOptionsSelected = computed(() => {\n if (selectableOptions.value.length === 0) return false\n const currentList = cfg.value.lazy && isOpen.value ? buffer.value : selection.value\n return selectableOptions.value.every((o) => o.value && currentList.some((s) => s.value === o.value))\n})\n\nfunction isSelected(value: string): boolean {\n const list = cfg.value.lazy && isOpen.value ? buffer : selection\n return list.value.some((s) => s.value === value)\n}\n\nfunction toggleAllOptions() {\n const currentList = cfg.value.lazy && isOpen.value ? buffer : selection\n const selectableOpts = selectableOptions.value.filter((o) => o.value)\n\n if (allOptionsSelected.value) {\n const selectableValues = new Set(selectableOpts.map((o) => o.value as string))\n currentList.value = currentList.value.filter((s) => !selectableValues.has(s.value ?? ''))\n } else {\n const existingValues = new Set(currentList.value.map((s) => s.value))\n const toAdd = selectableOpts.filter((o) => !existingValues.has(o.value as string))\n currentList.value = [...currentList.value, ...toAdd]\n }\n\n if (!cfg.value.lazy) {\n emit('update:modelValue', selection.value.length > 0 ? [...selection.value] : null)\n }\n}\n\nfunction toggleList(list: DropdownOption[], opt: DropdownOption): DropdownOption[] {\n const idx = list.findIndex((s) => s.value === opt.value)\n return idx >= 0 ? list.filter((_, i) => i !== idx) : [...list, opt]\n}\n\nfunction selectOption(opt: DropdownOption) {\n if (opt.callback) {\n opt.callback()\n isOpen.value = false\n return\n }\n\n const value = opt.value\n if (!value) return\n\n if (cfg.value.multiple) {\n if (cfg.value.lazy) {\n buffer.value = toggleList(buffer.value, opt)\n } else {\n selection.value = toggleList(selection.value, opt)\n emit('update:modelValue', selection.value.length > 0 ? [...selection.value] : null)\n }\n } else {\n selection.value = [opt]\n emit('update:modelValue', opt)\n isOpen.value = false\n }\n}\n\nfunction confirm() {\n if (cfg.value.lazy) {\n selection.value = [...buffer.value]\n emit('update:modelValue', buffer.value.length > 0 ? [...buffer.value] : null)\n }\n isOpen.value = false\n}\n\nfunction clear() {\n if (cfg.value.lazy) {\n buffer.value = []\n } else {\n selection.value = []\n emit('update:modelValue', null)\n }\n}\n\nfunction onOptionKeydown(e: KeyboardEvent, opt: DropdownOption) {\n if (e.key === ' ') {\n e.preventDefault()\n selectOption(opt)\n } else if (e.key === 'Enter') {\n e.preventDefault()\n confirm()\n }\n}\n\nfunction toggleOpen() {\n if (cfg.value.disabled) return\n isOpen.value = !isOpen.value\n if (isOpen.value) {\n if (cfg.value.filterable) {\n filterText.value = ''\n emit('filter-input', '')\n }\n }\n}\n\nfunction clearInput() {\n if (cfg.value.disabled) return\n selection.value = []\n emit('update:modelValue', null)\n isOpen.value = false\n}\n\nfunction focusAndOpen() {\n if (cfg.value.disabled) return\n isOpen.value = true\n if (cfg.value.filterable) nextTick(() => filterInputRef.value?.focus())\n}\n\nfunction handleFilterClear() {\n filterText.value = ''\n emit('filter-input', '')\n}\n\ndefineExpose({ focusAndOpen })\n</script>\n\n<template>\n <div class=\"ac-component\">\n <div ref=\"wrapperRef\" class=\"c-wrapper ds-wrapper\">\n <div\n class=\"c-input-row pointer\"\n :class=\"{\n 'c-input-row--sm': cfg.size === 'small',\n 'c-input-row--lg': cfg.size === 'large',\n 'c-input-row--disabled': cfg.disabled,\n 'c-input-row--open': isOpen,\n }\"\n :aria-disabled=\"cfg.disabled || undefined\"\n @click=\"toggleOpen()\"\n >\n <span v-if=\"selectedLabel\" class=\"c-truncate ds-value\">{{ selectedLabel }}</span>\n <span v-else class=\"c-placeholder\">{{ cfg.placeholder }}</span>\n <button\n v-if=\"cfg.clearable && selection.length > 0\"\n type=\"button\"\n class=\"c-icon-btn c-icon-btn--clear ds-clear-btn\"\n @click.stop=\"clearInput()\"\n aria-label=\"Törlés\"\n >\n <i class=\"fa-solid fa-fw fa-xmark\"></i>\n </button>\n <span\n class=\"c-icon-btn c-icon-btn--chevron mr-2\"\n :class=\"{ 'c-icon-btn--chevron-open': isOpen }\"\n >\n <i class=\"fa-solid fa-fw fa-chevron-down\"></i>\n </span>\n </div>\n </div>\n <Teleport to=\"body\">\n <div class=\"ac-component\">\n <div\n v-if=\"isOpen\"\n ref=\"dropdownRef\"\n class=\"c-dropdown ds-dropdown ds-wrapper\"\n :class=\"{ 'ds-dropdown--multiple': cfg.multiple, 'ds-dropdown--up': placement === 'up' }\"\n :style=\"dropdownStyle\"\n >\n <div v-if=\"cfg.filterable\" class=\"ds-filter\">\n <span\n v-if=\"cfg.multiple\"\n class=\"c-checkbox ds-select-all-checkbox\"\n :class=\"{ 'c-checkbox--checked': allOptionsSelected }\"\n @click.stop=\"toggleAllOptions()\"\n :title=\"allOptionsSelected ? 'Összes kijelölés törlése' : 'Összes kijelölése'\"\n ></span>\n <input\n ref=\"filterInputRef\"\n type=\"text\"\n id=\"ds-filter-input\"\n class=\"c-focus ds-filter-input\"\n :value=\"filterText\"\n @input=\"onFilterInput(($event.target as HTMLInputElement).value)\"\n autocomplete=\"off\"\n :placeholder=\"cfg.filterPlaceholder\"\n @click.stop\n />\n <button\n v-if=\"filterText\"\n type=\"button\"\n class=\"c-icon-btn c-icon-btn--clear ds-filter-clear\"\n @click.stop=\"handleFilterClear()\"\n aria-label=\"Szűrők törlése\"\n >\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n\n <ul class=\"ds-options c-scroll\">\n <li v-if=\"cfg.loading\" class=\"ds-option ds-option--loading\">\n <Loader size=\"2rem\" color=\"var(--neutral-300)\" class=\"m-auto p-3\" />\n </li>\n <template v-else>\n <li\n v-for=\"(opt, idx) in filteredOptions\"\n :key=\"opt.value ?? `cb-${idx}`\"\n class=\"d-option ds-option\"\n :class=\"{ 'ds-option--selected': opt.value && isSelected(opt.value) }\"\n tabindex=\"0\"\n @click=\"selectOption(opt)\"\n @keydown=\"onOptionKeydown($event, opt)\"\n >\n <span\n v-if=\"cfg.multiple && opt.value\"\n class=\"c-checkbox\"\n :class=\"{ 'c-checkbox--checked': isSelected(opt.value) }\"\n ></span>\n <i v-if=\"opt.icon\" class=\"fa-fw\" :class=\"opt.icon\"></i>\n <span\n class=\"d-option__label\"\n :class=\"{ 'c-truncate': cfg.textEllipsis }\"\n v-html=\"highlight(opt.label)\"\n ></span>\n </li>\n <li v-if=\"filteredOptions.length === 0\" class=\"ds-option ds-option--empty\">\n Nincs találat\n </li>\n </template>\n </ul>\n <div v-if=\"cfg.multiple\" class=\"c-footer\">\n <Button v-if=\"cfg.clearable && selection.length > 0\" label=\"Törlés\" outline @click=\"clear\" />\n <Button label=\"OK\" type=\"success\" @click=\"confirm\" />\n </div>\n </div>\n </div>\n </Teleport>\n </div>\n</template>\n\n<style lang=\"scss\" src=\"@/styles/components/dropdown-select.scss\"></style>\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"admins-components28.js","names":[],"sources":["../src/components/DropdownSelect.vue"],"sourcesContent":["<script lang=\"ts\">\nexport interface DropdownSelectConfig {\n placeholder?: string\n filterable?: boolean\n filterPlaceholder?: string\n clearable?: boolean\n textEllipsis?: boolean\n multiple?: boolean\n lazy?: boolean\n size?: ControlSize\n loading?: boolean\n highlight?: boolean\n disabled?: boolean\n}\n\nexport const dropdownSelectConfigDefaults: DropdownSelectConfig = {\n placeholder: 'Válassz...',\n filterable: true,\n filterPlaceholder: 'Kezdj el gépelni...',\n clearable: true,\n textEllipsis: true,\n multiple: false,\n lazy: false,\n loading: false,\n size: 'normal' as ControlSize,\n highlight: true,\n disabled: false,\n}\n\nexport interface DropdownOption {\n icon?: string\n value?: string\n label: string\n callback?: () => void\n}\n\nexport interface DropdownSelectProps {\n modelValue?: DropdownOption | DropdownOption[] | string | string[] | null\n options: DropdownOption[]\n config?: DropdownSelectConfig\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { ref, computed, watch, nextTick } from 'vue'\nimport Button from '@/components/Button.vue'\nimport type { ControlSize } from '@/types/types'\nimport Loader from '@/components/Loader.vue'\nimport { useDropdownAnchor } from '@/composables/useDropdownAnchor'\n\nconst props = withDefaults(defineProps<DropdownSelectProps>(), {\n modelValue: null,\n config: () => ({ ...dropdownSelectConfigDefaults }),\n})\n\nconst cfg = computed(() => ({ ...dropdownSelectConfigDefaults, ...props.config }))\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: DropdownOption | DropdownOption[] | null]\n 'filter-input': [filterText: string]\n}>()\n\nconst filterText = ref('')\nconst wrapperRef = ref<HTMLElement | null>(null)\nconst dropdownRef = ref<HTMLElement | null>(null)\nconst filterInputRef = ref<HTMLInputElement | null>(null)\nconst buffer = ref<DropdownOption[]>([])\nconst selection = ref<DropdownOption[]>(normalizeToOptions(props.modelValue, props.options))\n\nconst { isOpen, dropdownStyle, placement } = useDropdownAnchor(wrapperRef, dropdownRef, {\n extraStyle: (rect) => ({\n minWidth: `${rect.width}px`,\n maxWidth: `${rect.width}px`,\n }),\n maxHeight: '17rem',\n})\n\n\nfunction normalizeToOptions(\n val: DropdownOption | DropdownOption[] | string | string[] | null | undefined,\n options: DropdownOption[],\n): DropdownOption[] {\n if (val == null) return []\n const arr = Array.isArray(val) ? val : [val]\n return arr\n .map((entry): DropdownOption | null => {\n if (entry == null) return null\n if (typeof entry === 'object' && 'label' in entry) {\n return entry as DropdownOption\n }\n if (typeof entry === 'string') {\n const found = options.find((o) => o.value === entry)\n return found ?? { value: entry, label: entry }\n }\n return null\n })\n .filter((o): o is DropdownOption => o !== null)\n}\n\nwatch(\n () => [props.modelValue, props.options],\n ([v]) => {\n selection.value = normalizeToOptions(v as typeof props.modelValue, props.options)\n },\n)\n\nwatch(isOpen, (open) => {\n if (open) {\n filterText.value = ''\n if (cfg.value.filterable) nextTick(() => filterInputRef.value?.focus())\n if (cfg.value.lazy) buffer.value = [...selection.value]\n }\n})\n\nfunction onFilterInput(text: string) {\n filterText.value = text\n emit('filter-input', text)\n}\n\nconst selectedLabel = computed(() => {\n if (selection.value.length === 0) return null\n if (!cfg.value.multiple) {\n const sel = selection.value[0]\n\n return props.options.find((o) => o.value === sel?.value)?.label ?? sel?.label ?? null\n }\n if (selection.value.length > 2) return `${selection.value.length} kiválasztva`\n return selection.value\n .map((sel) => props.options.find((o) => o.value === sel.value)?.label ?? sel.label ?? sel.value)\n .join(', ')\n})\n\nconst filteredOptions = computed(() => {\n const q = filterText.value.toLowerCase()\n return q ? props.options.filter((o) => o.label.toLowerCase().includes(q)) : props.options\n})\n\nfunction escapeHtml(str: string) {\n return str.replace(\n /[&<>\"']/g,\n (m) => ({ '&': '&', '<': '<', '>': '>', '\"': '"', \"'\": ''' })[m]!,\n )\n}\n\nfunction highlight(label: string) {\n const q = filterText.value.trim()\n if (!q || !cfg.value.highlight) return escapeHtml(label)\n\n const safeLabel = escapeHtml(label)\n const safeQ = escapeHtml(q)\n\n const re = new RegExp(safeQ.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'ig')\n return safeLabel.replace(re, (m) => `<mark class=\"ds-option__highlight\">${m}</mark>`)\n}\n\nconst selectableOptions = computed(() => {\n return filteredOptions.value.filter((o) => o.value)\n})\n\nconst allOptionsSelected = computed(() => {\n if (selectableOptions.value.length === 0) return false\n const currentList = cfg.value.lazy && isOpen.value ? buffer.value : selection.value\n return selectableOptions.value.every((o) => o.value && currentList.some((s) => s.value === o.value))\n})\n\nfunction isSelected(value: string): boolean {\n const list = cfg.value.lazy && isOpen.value ? buffer : selection\n return list.value.some((s) => s.value === value)\n}\n\nfunction toggleAllOptions() {\n const currentList = cfg.value.lazy && isOpen.value ? buffer : selection\n const selectableOpts = selectableOptions.value.filter((o) => o.value)\n\n if (allOptionsSelected.value) {\n const selectableValues = new Set(selectableOpts.map((o) => o.value as string))\n currentList.value = currentList.value.filter((s) => !selectableValues.has(s.value ?? ''))\n } else {\n const existingValues = new Set(currentList.value.map((s) => s.value))\n const toAdd = selectableOpts.filter((o) => !existingValues.has(o.value as string))\n currentList.value = [...currentList.value, ...toAdd]\n }\n\n if (!cfg.value.lazy) {\n emit('update:modelValue', selection.value.length > 0 ? [...selection.value] : null)\n }\n}\n\nfunction toggleList(list: DropdownOption[], opt: DropdownOption): DropdownOption[] {\n const idx = list.findIndex((s) => s.value === opt.value)\n return idx >= 0 ? list.filter((_, i) => i !== idx) : [...list, opt]\n}\n\nfunction selectOption(opt: DropdownOption) {\n if (opt.callback) {\n opt.callback()\n isOpen.value = false\n return\n }\n\n const value = opt.value\n if (!value) return\n\n if (cfg.value.multiple) {\n if (cfg.value.lazy) {\n buffer.value = toggleList(buffer.value, opt)\n } else {\n selection.value = toggleList(selection.value, opt)\n emit('update:modelValue', selection.value.length > 0 ? [...selection.value] : null)\n }\n } else {\n selection.value = [opt]\n emit('update:modelValue', opt)\n isOpen.value = false\n }\n}\n\nfunction confirm() {\n if (cfg.value.lazy) {\n selection.value = [...buffer.value]\n emit('update:modelValue', buffer.value.length > 0 ? [...buffer.value] : null)\n }\n isOpen.value = false\n}\n\nfunction clear() {\n if (cfg.value.lazy) {\n buffer.value = []\n } else {\n selection.value = []\n emit('update:modelValue', null)\n }\n}\n\nfunction onOptionKeydown(e: KeyboardEvent, opt: DropdownOption) {\n if (e.key === ' ') {\n e.preventDefault()\n selectOption(opt)\n } else if (e.key === 'Enter') {\n e.preventDefault()\n confirm()\n }\n}\n\nfunction toggleOpen() {\n if (cfg.value.disabled) return\n isOpen.value = !isOpen.value\n if (isOpen.value) {\n if (cfg.value.filterable) {\n filterText.value = ''\n emit('filter-input', '')\n }\n }\n}\n\nfunction clearInput() {\n if (cfg.value.disabled) return\n selection.value = []\n emit('update:modelValue', null)\n isOpen.value = false\n}\n\nfunction focusAndOpen() {\n if (cfg.value.disabled) return\n isOpen.value = true\n if (cfg.value.filterable) nextTick(() => filterInputRef.value?.focus())\n}\n\nfunction handleFilterClear() {\n filterText.value = ''\n emit('filter-input', '')\n}\n\ndefineExpose({ focusAndOpen })\n</script>\n\n<template>\n <div class=\"ac-component\">\n <div ref=\"wrapperRef\" class=\"c-wrapper ds-wrapper\">\n <div\n class=\"c-input-row pointer\"\n :class=\"{\n 'c-input-row--sm': cfg.size === 'small',\n 'c-input-row--lg': cfg.size === 'large',\n 'c-input-row--disabled': cfg.disabled,\n 'c-input-row--open': isOpen,\n }\"\n :aria-disabled=\"cfg.disabled || undefined\"\n @click=\"toggleOpen()\"\n >\n <span v-if=\"selectedLabel\" class=\"c-truncate ds-value\">{{ selectedLabel }}</span>\n <span v-else class=\"c-placeholder\">{{ cfg.placeholder }}</span>\n <button\n v-if=\"cfg.clearable && selection.length > 0\"\n type=\"button\"\n class=\"c-icon-btn c-icon-btn--clear ds-clear-btn\"\n @click.stop=\"clearInput()\"\n aria-label=\"Törlés\"\n >\n <i class=\"fa-solid fa-fw fa-xmark\"></i>\n </button>\n <span\n class=\"c-icon-btn c-icon-btn--chevron mr-2\"\n :class=\"{ 'c-icon-btn--chevron-open': isOpen }\"\n >\n <i class=\"fa-solid fa-fw fa-chevron-down\"></i>\n </span>\n </div>\n </div>\n <Teleport to=\"body\">\n <div class=\"ac-component\">\n <div\n v-if=\"isOpen\"\n ref=\"dropdownRef\"\n class=\"c-dropdown ds-dropdown ds-wrapper\"\n :class=\"{ 'ds-dropdown--multiple': cfg.multiple, 'ds-dropdown--up': placement === 'up' }\"\n :style=\"dropdownStyle\"\n >\n <div v-if=\"cfg.filterable\" class=\"ds-filter\">\n <span\n v-if=\"cfg.multiple\"\n class=\"c-checkbox ds-select-all-checkbox\"\n :class=\"{ 'c-checkbox--checked': allOptionsSelected }\"\n @click.stop=\"toggleAllOptions()\"\n :title=\"allOptionsSelected ? 'Összes kijelölés törlése' : 'Összes kijelölése'\"\n ></span>\n <input\n ref=\"filterInputRef\"\n type=\"text\"\n id=\"ds-filter-input\"\n class=\"c-focus ds-filter-input\"\n :value=\"filterText\"\n @input=\"onFilterInput(($event.target as HTMLInputElement).value)\"\n autocomplete=\"off\"\n :placeholder=\"cfg.filterPlaceholder\"\n @click.stop\n />\n <button\n v-if=\"filterText\"\n type=\"button\"\n class=\"c-icon-btn c-icon-btn--clear ds-filter-clear\"\n @click.stop=\"handleFilterClear()\"\n aria-label=\"Szűrők törlése\"\n >\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n\n <ul class=\"ds-options c-scroll\">\n <li v-if=\"cfg.loading\" class=\"ds-option ds-option--loading\">\n <Loader size=\"2rem\" color=\"var(--neutral-300)\" class=\"m-auto p-3\" />\n </li>\n <template v-else>\n <li\n v-for=\"(opt, idx) in filteredOptions\"\n :key=\"opt.value ?? `cb-${idx}`\"\n class=\"d-option ds-option\"\n :class=\"{ 'ds-option--selected': opt.value && isSelected(opt.value) }\"\n tabindex=\"0\"\n @click=\"selectOption(opt)\"\n @keydown=\"onOptionKeydown($event, opt)\"\n >\n <span\n v-if=\"cfg.multiple && opt.value\"\n class=\"c-checkbox\"\n :class=\"{ 'c-checkbox--checked': isSelected(opt.value) }\"\n ></span>\n <i v-if=\"opt.icon\" class=\"fa-fw\" :class=\"opt.icon\"></i>\n <span\n class=\"d-option__label\"\n :class=\"{ 'c-truncate': cfg.textEllipsis }\"\n v-html=\"highlight(opt.label)\"\n ></span>\n </li>\n <li v-if=\"filteredOptions.length === 0\" class=\"ds-option ds-option--empty\">\n Nincs találat\n </li>\n </template>\n </ul>\n <div v-if=\"cfg.multiple\" class=\"c-footer\">\n <Button v-if=\"cfg.clearable && selection.length > 0\" label=\"Törlés\" outline @click=\"clear\" />\n <Button label=\"OK\" type=\"success\" @click=\"confirm\" />\n </div>\n </div>\n </div>\n </Teleport>\n </div>\n</template>\n\n<style lang=\"scss\" src=\"@/styles/components/dropdown-select.scss\"></style>\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"admins-components28.js","names":[],"sources":["../src/components/DropdownSelect.vue"],"sourcesContent":["<script lang=\"ts\">\nexport interface DropdownSelectConfig {\n placeholder?: string\n filterable?: boolean\n filterPlaceholder?: string\n clearable?: boolean\n textEllipsis?: boolean\n multiple?: boolean\n lazy?: boolean\n size?: ControlSize\n loading?: boolean\n highlight?: boolean\n disabled?: boolean\n}\n\nexport const dropdownSelectConfigDefaults: DropdownSelectConfig = {\n placeholder: 'Válassz...',\n filterable: true,\n filterPlaceholder: 'Kezdj el gépelni...',\n clearable: true,\n textEllipsis: true,\n multiple: false,\n lazy: false,\n loading: false,\n size: 'normal' as ControlSize,\n highlight: true,\n disabled: false,\n}\n\nexport interface DropdownOption {\n icon?: string\n value?: string\n label: string\n callback?: () => void\n}\n\nexport interface DropdownSelectProps {\n modelValue?: DropdownOption | DropdownOption[] | string | string[] | null\n options: DropdownOption[]\n config?: DropdownSelectConfig\n}\n</script>\n\n<script setup lang=\"ts\">\nimport { ref, computed, watch, nextTick } from 'vue'\nimport Button from '@/components/Button.vue'\nimport type { ControlSize } from '@/types/types'\nimport Loader from '@/components/Loader.vue'\nimport { useDropdownAnchor } from '@/composables/useDropdownAnchor'\n\nconst props = withDefaults(defineProps<DropdownSelectProps>(), {\n modelValue: null,\n config: () => ({ ...dropdownSelectConfigDefaults }),\n})\n\nconst cfg = computed(() => ({ ...dropdownSelectConfigDefaults, ...props.config }))\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: DropdownOption | DropdownOption[] | null]\n 'filter-input': [filterText: string]\n}>()\n\nconst filterText = ref('')\nconst wrapperRef = ref<HTMLElement | null>(null)\nconst dropdownRef = ref<HTMLElement | null>(null)\nconst filterInputRef = ref<HTMLInputElement | null>(null)\nconst buffer = ref<DropdownOption[]>([])\nconst selection = ref<DropdownOption[]>(normalizeToOptions(props.modelValue, props.options))\n\nconst { isOpen, dropdownStyle, placement } = useDropdownAnchor(wrapperRef, dropdownRef, {\n extraStyle: (rect) => ({\n minWidth: `${rect.width}px`,\n maxWidth: `${rect.width}px`,\n }),\n maxHeight: '20rem',\n})\n\n\nfunction normalizeToOptions(\n val: DropdownOption | DropdownOption[] | string | string[] | null | undefined,\n options: DropdownOption[],\n): DropdownOption[] {\n if (val == null) return []\n const arr = Array.isArray(val) ? val : [val]\n return arr\n .map((entry): DropdownOption | null => {\n if (entry == null) return null\n if (typeof entry === 'object' && 'label' in entry) {\n return entry as DropdownOption\n }\n if (typeof entry === 'string') {\n const found = options.find((o) => o.value === entry)\n return found ?? { value: entry, label: entry }\n }\n return null\n })\n .filter((o): o is DropdownOption => o !== null)\n}\n\nwatch(\n () => [props.modelValue, props.options],\n ([v]) => {\n selection.value = normalizeToOptions(v as typeof props.modelValue, props.options)\n },\n)\n\nwatch(isOpen, (open) => {\n if (open) {\n filterText.value = ''\n if (cfg.value.filterable) nextTick(() => filterInputRef.value?.focus())\n if (cfg.value.lazy) buffer.value = [...selection.value]\n }\n})\n\nfunction onFilterInput(text: string) {\n filterText.value = text\n emit('filter-input', text)\n}\n\nconst selectedLabel = computed(() => {\n if (selection.value.length === 0) return null\n if (!cfg.value.multiple) {\n const sel = selection.value[0]\n\n return props.options.find((o) => o.value === sel?.value)?.label ?? sel?.label ?? null\n }\n if (selection.value.length > 2) return `${selection.value.length} kiválasztva`\n return selection.value\n .map((sel) => props.options.find((o) => o.value === sel.value)?.label ?? sel.label ?? sel.value)\n .join(', ')\n})\n\nconst filteredOptions = computed(() => {\n const q = filterText.value.toLowerCase()\n return q ? props.options.filter((o) => o.label.toLowerCase().includes(q)) : props.options\n})\n\nfunction escapeHtml(str: string) {\n return str.replace(\n /[&<>\"']/g,\n (m) => ({ '&': '&', '<': '<', '>': '>', '\"': '"', \"'\": ''' })[m]!,\n )\n}\n\nfunction highlight(label: string) {\n const q = filterText.value.trim()\n if (!q || !cfg.value.highlight) return escapeHtml(label)\n\n const safeLabel = escapeHtml(label)\n const safeQ = escapeHtml(q)\n\n const re = new RegExp(safeQ.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'ig')\n return safeLabel.replace(re, (m) => `<mark class=\"ds-option__highlight\">${m}</mark>`)\n}\n\nconst selectableOptions = computed(() => {\n return filteredOptions.value.filter((o) => o.value)\n})\n\nconst allOptionsSelected = computed(() => {\n if (selectableOptions.value.length === 0) return false\n const currentList = cfg.value.lazy && isOpen.value ? buffer.value : selection.value\n return selectableOptions.value.every((o) => o.value && currentList.some((s) => s.value === o.value))\n})\n\nfunction isSelected(value: string): boolean {\n const list = cfg.value.lazy && isOpen.value ? buffer : selection\n return list.value.some((s) => s.value === value)\n}\n\nfunction toggleAllOptions() {\n const currentList = cfg.value.lazy && isOpen.value ? buffer : selection\n const selectableOpts = selectableOptions.value.filter((o) => o.value)\n\n if (allOptionsSelected.value) {\n const selectableValues = new Set(selectableOpts.map((o) => o.value as string))\n currentList.value = currentList.value.filter((s) => !selectableValues.has(s.value ?? ''))\n } else {\n const existingValues = new Set(currentList.value.map((s) => s.value))\n const toAdd = selectableOpts.filter((o) => !existingValues.has(o.value as string))\n currentList.value = [...currentList.value, ...toAdd]\n }\n\n if (!cfg.value.lazy) {\n emit('update:modelValue', selection.value.length > 0 ? [...selection.value] : null)\n }\n}\n\nfunction toggleList(list: DropdownOption[], opt: DropdownOption): DropdownOption[] {\n const idx = list.findIndex((s) => s.value === opt.value)\n return idx >= 0 ? list.filter((_, i) => i !== idx) : [...list, opt]\n}\n\nfunction selectOption(opt: DropdownOption) {\n if (opt.callback) {\n opt.callback()\n isOpen.value = false\n return\n }\n\n const value = opt.value\n if (!value) return\n\n if (cfg.value.multiple) {\n if (cfg.value.lazy) {\n buffer.value = toggleList(buffer.value, opt)\n } else {\n selection.value = toggleList(selection.value, opt)\n emit('update:modelValue', selection.value.length > 0 ? [...selection.value] : null)\n }\n } else {\n selection.value = [opt]\n emit('update:modelValue', opt)\n isOpen.value = false\n }\n}\n\nfunction confirm() {\n if (cfg.value.lazy) {\n selection.value = [...buffer.value]\n emit('update:modelValue', buffer.value.length > 0 ? [...buffer.value] : null)\n }\n isOpen.value = false\n}\n\nfunction clear() {\n if (cfg.value.lazy) {\n buffer.value = []\n } else {\n selection.value = []\n emit('update:modelValue', null)\n }\n}\n\nfunction onOptionKeydown(e: KeyboardEvent, opt: DropdownOption) {\n if (e.key === ' ') {\n e.preventDefault()\n selectOption(opt)\n } else if (e.key === 'Enter') {\n e.preventDefault()\n confirm()\n }\n}\n\nfunction toggleOpen() {\n if (cfg.value.disabled) return\n isOpen.value = !isOpen.value\n if (isOpen.value) {\n if (cfg.value.filterable) {\n filterText.value = ''\n emit('filter-input', '')\n }\n }\n}\n\nfunction clearInput() {\n if (cfg.value.disabled) return\n selection.value = []\n emit('update:modelValue', null)\n isOpen.value = false\n}\n\nfunction focusAndOpen() {\n if (cfg.value.disabled) return\n isOpen.value = true\n if (cfg.value.filterable) nextTick(() => filterInputRef.value?.focus())\n}\n\nfunction handleFilterClear() {\n filterText.value = ''\n emit('filter-input', '')\n}\n\ndefineExpose({ focusAndOpen })\n</script>\n\n<template>\n <div class=\"ac-component\">\n <div ref=\"wrapperRef\" class=\"c-wrapper ds-wrapper\">\n <div\n class=\"c-input-row pointer\"\n :class=\"{\n 'c-input-row--sm': cfg.size === 'small',\n 'c-input-row--lg': cfg.size === 'large',\n 'c-input-row--disabled': cfg.disabled,\n 'c-input-row--open': isOpen,\n }\"\n :aria-disabled=\"cfg.disabled || undefined\"\n @click=\"toggleOpen()\"\n >\n <span v-if=\"selectedLabel\" class=\"c-truncate ds-value\">{{ selectedLabel }}</span>\n <span v-else class=\"c-placeholder\">{{ cfg.placeholder }}</span>\n <button\n v-if=\"cfg.clearable && selection.length > 0\"\n type=\"button\"\n class=\"c-icon-btn c-icon-btn--clear ds-clear-btn\"\n @click.stop=\"clearInput()\"\n aria-label=\"Törlés\"\n >\n <i class=\"fa-solid fa-fw fa-xmark\"></i>\n </button>\n <span\n class=\"c-icon-btn c-icon-btn--chevron mr-2\"\n :class=\"{ 'c-icon-btn--chevron-open': isOpen }\"\n >\n <i class=\"fa-solid fa-fw fa-chevron-down\"></i>\n </span>\n </div>\n </div>\n <Teleport to=\"body\">\n <div class=\"ac-component\">\n <div\n v-if=\"isOpen\"\n ref=\"dropdownRef\"\n class=\"c-dropdown ds-dropdown ds-wrapper\"\n :class=\"{ 'ds-dropdown--multiple': cfg.multiple, 'ds-dropdown--up': placement === 'up' }\"\n :style=\"dropdownStyle\"\n >\n <div v-if=\"cfg.filterable\" class=\"ds-filter\">\n <span\n v-if=\"cfg.multiple\"\n class=\"c-checkbox ds-select-all-checkbox\"\n :class=\"{ 'c-checkbox--checked': allOptionsSelected }\"\n @click.stop=\"toggleAllOptions()\"\n :title=\"allOptionsSelected ? 'Összes kijelölés törlése' : 'Összes kijelölése'\"\n ></span>\n <input\n ref=\"filterInputRef\"\n type=\"text\"\n id=\"ds-filter-input\"\n class=\"c-focus ds-filter-input\"\n :value=\"filterText\"\n @input=\"onFilterInput(($event.target as HTMLInputElement).value)\"\n autocomplete=\"off\"\n :placeholder=\"cfg.filterPlaceholder\"\n @click.stop\n />\n <button\n v-if=\"filterText\"\n type=\"button\"\n class=\"c-icon-btn c-icon-btn--clear ds-filter-clear\"\n @click.stop=\"handleFilterClear()\"\n aria-label=\"Szűrők törlése\"\n >\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n\n <ul class=\"ds-options c-scroll\">\n <li v-if=\"cfg.loading\" class=\"ds-option ds-option--loading\">\n <Loader size=\"2rem\" color=\"var(--neutral-300)\" class=\"m-auto p-3\" />\n </li>\n <template v-else>\n <li\n v-for=\"(opt, idx) in filteredOptions\"\n :key=\"opt.value ?? `cb-${idx}`\"\n class=\"d-option ds-option\"\n :class=\"{ 'ds-option--selected': opt.value && isSelected(opt.value) }\"\n tabindex=\"0\"\n @click=\"selectOption(opt)\"\n @keydown=\"onOptionKeydown($event, opt)\"\n >\n <span\n v-if=\"cfg.multiple && opt.value\"\n class=\"c-checkbox\"\n :class=\"{ 'c-checkbox--checked': isSelected(opt.value) }\"\n ></span>\n <i v-if=\"opt.icon\" class=\"fa-fw\" :class=\"opt.icon\"></i>\n <span\n class=\"d-option__label\"\n :class=\"{ 'c-truncate': cfg.textEllipsis }\"\n v-html=\"highlight(opt.label)\"\n ></span>\n </li>\n <li v-if=\"filteredOptions.length === 0\" class=\"ds-option ds-option--empty\">\n Nincs találat\n </li>\n </template>\n </ul>\n <div v-if=\"cfg.multiple\" class=\"c-footer\">\n <Button v-if=\"cfg.clearable && selection.length > 0\" label=\"Törlés\" outline @click=\"clear\" />\n <Button label=\"OK\" type=\"success\" @click=\"confirm\" />\n </div>\n </div>\n </div>\n </Teleport>\n </div>\n</template>\n\n<style lang=\"scss\" src=\"@/styles/components/dropdown-select.scss\"></style>\n"],"mappings":""}
|