FileMaster
Search
Toggle Dark Mode
Home
/
.
/
wp-content
/
plugins
/
ameliabooking
/
v3
/
src
/
views
/
_components
/
advanced-select
Edit File: AmAdvancedSelect.vue
<template> <div ref="advSelectWrapperRef" class="am-adv-select__wrapper" > <el-cascader ref="advSelect" v-model="model" class="am-adv-select" :class="[ `am-adv-select--${size}`, {'am-adv-select--disabled': disabled}, {'am-rtl': isRtl} ]" :options="props.options" :props="props.propsData" :placeholder="props.placeholder" :disabled="props.disabled" :clearable="props.clearable" :show-all-levels="props.showAllLevels" :collapse-tags="props.collapseTags" :collapse-tags-tooltip="props.collapseTagsTooltip" :separator="props.separator" :filterable="props.filterable" :filter-method="props.filterMethod" :debounce="props.debounce" :before-filter="props.beforeFilter" :popper-class="popperClasses" :teleported="props.teleported" :tag-type="props.tagType" :tag-effect="props.tagEffect" :validate-event="props.validateEvent" :max-collapse-tags="props.maxCollapseTags" :persistent="props.persistent" :fallback-placements="props.fallbackPlacements" :placement="props.placement" :style="cssVars" :aria-label="props.ariaLabel" @change="handleChange" @expand-change="handleExpandChange" @blur="(e) => emits('blur', e)" @focus="(e) => emits('focus', e)" @visible-change="handleVisibleChange" @remove-tag="(val) => emits('remove-tag', val)" > <template v-if="props.prefixIcon" #prefix> <component :is="props.prefixIcon" v-if="typeof props.prefixIcon === 'object'" /> <span v-if="typeof props.prefixIcon === 'string'" :class="`am-icon-${props.prefixIcon}`" /> </template> <template #empty> <span> {{ emptyStateString }} </span> </template> <template #default="{node, data}"> <div v-if="!node.isLeaf" class="am-adv-select__item" :style="cssDropdownVars" > <span class="am-adv-select__item-label"> {{ data[props.propsData.label] }} </span> <span class="am-adv-select__item-quantity"> {{ `(${data[props.propsData.children].length})` }} </span> </div> <div v-if="node.isLeaf" class="am-adv-select__item" :class="{'am-adv-select__item-checked': node.checked}" :style="cssDropdownVars" > <span class="am-adv-select__item-label"> {{ data[props.propsData.label] }} </span> <span v-if="data.price" class="am-adv-select__item-price"> {{` ${useFormattedPrice(data.price)}` }} <span v-if="taxVisibility(data.id)" class="am-adv-select__item-tax" > <template v-if="props.taxOptions.find(a => a.id === data.id).excluded"> {{ props.taxLabel }} </template> <template v-else> {{props.taxLabelIncl}} </template> </span> </span> </div> </template> </el-cascader> <teleport v-if="teleportCategoryDisable && categoryName" :to="`${popperId} .am-adv-select__popper-${uniqueClassSuffix} .el-cascader-panel .el-cascader-menu:nth-child(1)`" :disabled="!teleportCategoryDisable && categoryName" > <span v-if="options.length" class="am-adv-select__popper-heading" :style="cssTeleport"> {{ categoryName }} </span> </teleport> <teleport v-if="teleportSubCategoryDisable && subCategoryName" :to="`${popperId} .am-adv-select__popper-${uniqueClassSuffix} .el-cascader-panel .el-cascader-menu:nth-child(2)`" :disabled="!teleportSubCategoryDisable && subCategoryName" > <span v-if="options.length" class="am-adv-select__popper-heading" :style="cssTeleport"> {{ subCategoryName }} </span> </teleport> </div> </template> <script setup> import { computed, inject, nextTick, ref, toRefs } from 'vue' import { useColorTransparency } from "../../../assets/js/common/colorManipulation"; import { useFormattedPrice } from '../../../assets/js/common/formatting' import { useElementSize } from '@vueuse/core' /** * Component Props */ const props = defineProps({ id: { type: String }, modelValue: { type: [String, Array, Object, Number], }, options: { // * data of the options, the key of value and label can be customize by CascaderProps type: Array, default: () => [] }, propsData: { // * configuration options, see the following CascaderProps table. type: Object, }, size: { // default / medium / small / mini / micro type: String, default: 'default', validator(value) { return ['default', 'medium', 'small', 'mini', 'micro'].includes(value) } }, placeholder: { type: String, default: '' }, disabled: { // * whether Cascader is disabled type: Boolean, default: false }, clearable: { // * whether selected value can be cleared type: Boolean, default: true, }, showAllLevels: { // * whether to display all levels of the selected value in the input type: Boolean, default: true }, collapseTags: { // * whether to collapse tags in multiple selection mode type: Boolean, default: true }, collapseTagsTooltip: { // * whether show all selected tags when mouse hover text of collapse-tags. To use this, collapse-tags must be true type: Boolean, default: false }, separator: { // * option label separator type: String, default: ' / ' }, filterable: { // * whether to filter options type: Boolean, default: true }, filterMethod: { // * customize search logic, the first parameter is node, the second is keyword, and need return a boolean value indicating whether it hits. type: Function, default: (node, keyword) => { let search = keyword.toLowerCase() let label = node.text.toLowerCase() return label.includes(search) } }, debounce: { // * debounce delay when typing filter keyword, in milliseconds type: Number, default: 300 }, beforeFilter: { // * hook function before filtering with the value to be filtered as its parameter. If false is returned or a Promise is returned and then is rejected, filtering will be aborted type: Function }, popperClass: { // * custom class name for Cascader's dropdown type: String, default: '' }, teleported: { // * whether cascader popup is teleported type: Boolean, default: true }, tagType: { // * tag type type: String, default: 'info', validator(value) { return ['info', 'success', 'warning', 'danger'].includes(value) } }, tagEffect: { // * tag effect type: String, default: 'light', validator(value) { return ['dark', 'light', 'plain'].includes(value) } }, validateEvent: { // * event name that triggers validation type: Boolean, default: true }, maxCollapseTags: { // * The max tags number to be shown. To use this, collpase-tags must be true type: Number, default: 1 }, persistent: { // * when dropdown is inactive and persistent is false, dropdown will be destroyed type: Boolean, default: true }, fallbackPlacements: { // * ist of possible positions for Tooltip popper.js type: Array, default: () => ['bottom-start', 'top-start', 'right', 'left'] }, placement: { // * placement of the dropdown, default is bottom-start type: String, default: 'bottom-start', validator(value) { return [ 'top', 'top-start', 'top-end', 'bottom', 'bottom-start', 'bottom-end', 'left', 'left-start', 'left-end', 'right', 'right-start', 'right-end' ].includes(value) }, }, prefixIcon: { type: [String, Object], default: '' }, currencySymbol: { type: String, default: '$' }, categoryName: { type: String, default: '' }, subCategoryName: { type: String, default: '' }, emptyStateString: { type: String, default: 'No matching data' }, taxOptions: { type: [Object, Array], default: () => { return [] } }, taxLabel: { type: String, default: '' }, taxLabelIncl: { type: String, default: '' }, taxVisible: { type: Boolean, default: true }, ariaLabel: { type: String, default: 'dropdown' }, }) /** * Component Emits * @type {EmitFn<(string)[]>} */ const emits = defineEmits(['change', 'expand-change', 'blur', 'focus', 'visible-change', 'remove-tag', 'update:modelValue']) // * Component model let { modelValue } = toRefs(props) let model = computed({ get: () => modelValue.value, set: (val) => { emits('update:modelValue', val) } }) // * Tat Visibility function taxVisibility (id) { return props.taxVisible && !!props.taxOptions.filter(a => a.id === id).length } // * Container Width let cWidth = inject('containerWidth', 0) let checkScreen = computed(() => cWidth.value < 560 || (cWidth.value > 560 && cWidth.value < 640)) // * Element Wrapper Size const advSelectWrapperRef = ref(null) const {width: wrapperWidth} = useElementSize(advSelectWrapperRef) // * Component reference const advSelect = ref(null) // * Component text orientation let isRtl = computed(() => { if (document) { return document.documentElement.dir === 'rtl' } return false }) /** * Dropdown (Popper) ID */ const popperId = ref('') /** * Dropdown (Popper) identifier class */ let uniqueClassSuffix = ref(Math.floor(Math.random() * 1000) + 1) /** * Dropdown (Popper) Classes * @type {ComputedRef<string>} */ let popperClasses = computed(() => { return `am-adv-select__popper-${uniqueClassSuffix.value} am-adv-select__popper${props.popperClass ? ' ' + props.popperClass : ''}` + (checkScreen.value ? ' am-adv-select__popper-mobile':'') }) /** * Teleport Variables - category and subcategory name in drop down */ let teleportSubCategoryDisable = ref(false) let teleportCategoryDisable = ref(false) // * Fonts let amFonts = inject('amFonts', ref({ fontFamily: 'Amelia Roboto, sans-serif', fontUrl: '', customFontFamily: '', fontFormat: '', customFontSelected: false })) // * Colors let amColors = inject('amColors', ref({ colorPrimary: '#1246D6', colorSuccess: '#019719', colorError: '#B4190F', colorWarning: '#CCA20C', colorMainBgr: '#FFFFFF', colorMainHeadingText: '#33434C', colorMainText: '#1A2C37', colorSbBgr: '#17295A', colorSbText: '#FFFFFF', colorInpBgr: '#FFFFFF', colorInpBorder: '#D1D5D7', colorInpText: '#1A2C37', colorInpPlaceHolder: '#1A2C37', colorDropBgr: '#FFFFFF', colorDropBorder: '#D1D5D7', colorDropText: '#0E1920', colorBtnPrim: '#265CF2', colorBtnPrimText: '#FFFFFF', colorBtnSec: '#1A2C37', colorBtnSecText: '#FFFFFF', })) // * Adv css vars let cssVars = computed(() => { return { '--am-c-advs-bgr': amColors.value.colorInpBgr, '--am-c-advs-border': amColors.value.colorInpBorder, '--am-c-advs-text': amColors.value.colorInpText, '--am-c-advs-placeholder': amColors.value.colorInpPlaceHolder, '--am-c-advs-shadow': useColorTransparency(amColors.value.colorInpText, 0.05), '--am-c-advs-text-op60': useColorTransparency(amColors.value.colorInpText, 0.6), '--am-c-advs-text-op40': useColorTransparency(amColors.value.colorInpText, 0.4), '--am-c-advs-text-op10': useColorTransparency(amColors.value.colorInpText, 0.03), '--am-font-family': amFonts.value.fontFamily } }) // * Adv dropdown css vars let cssDropdownVars = computed(() => { return { '--am-c-advs-item-price': amColors.value.colorPrimary, '--am-c-advs-item-price-op10': useColorTransparency(amColors.value.colorPrimary, 0.1), '--am-c-advs-item-selected': amColors.value.colorPrimary, '--am-c-advs-item-label-op40': useColorTransparency(amColors.value.colorDropText, 0.4), '--am-font-family': amFonts.value.fontFamily } }) /** * Change Function * @param val */ function handleChange(val) { emits('change', val) emits('update:modelValue', val) } /** * Dropdown expand detection and width of dropdown control * @param val */ function handleExpandChange(val) { nextTick(() => { teleportSubCategoryDisable.value = true }) emits('expand-change', val) } /** * Dropdown visibility control * @param e */ function handleVisibleChange(e) { nextTick(() => { if (!e && !model.value) { teleportSubCategoryDisable.value = false } teleportCategoryDisable.value = true if (advSelect.value) { advSelect.value.contentRef.style.setProperty('--am-c-advs-item-bgr', amColors.value.colorDropBgr) advSelect.value.contentRef.style.setProperty('--am-c-advs-item-border', amColors.value.colorDropBorder) advSelect.value.contentRef.style.setProperty('--am-c-advs-item-bgr-op10', useColorTransparency(amColors.value.colorDropText, 0.1)) advSelect.value.contentRef.style.setProperty('--am-c-advs-item-label', amColors.value.colorDropText) advSelect.value.contentRef.style.setProperty('--am-c-advs-item-label-op65', useColorTransparency(amColors.value.colorDropText, 0.65)) advSelect.value.contentRef.style.setProperty('--am-c-advs-item-border-op10', useColorTransparency(amColors.value.colorDropText, 0.1)) advSelect.value.contentRef.style.setProperty('--am-font-family', amFonts.value.fontFamily) advSelect.value.contentRef.style.setProperty('width', `${wrapperWidth.value}px`) } }) emits('visible-change', e) } let cssTeleport = computed(() => { return { '--am-h-advs-item-heading': checkScreen.value ? '32px' : '26px', '--am-fs-advs-item-heading': checkScreen.value ? '16px' : '12px', '--am-c-advs-item-heading-op65': useColorTransparency(amColors.value.colorDropText, 0.65), '--am-c-advs-shadow': useColorTransparency(amColors.value.colorInpText, 0.05), } }) </script> <style lang="scss"> @mixin am-adv-select-block { // Adv Select .am-adv-select { // -c- color // -rad- border radius // -h- height // -fs- font size // -padd- padding // -bgr background // -advs- advanced select --am-c-advs-bgr: var(--am-c-inp-bgr); --am-c-advs-border: var(--am-c-inp-border); --am-c-advs-text: var(--am-c-inp-text); --am-c-advs-placeholder: var(--am-color-input-placeholder); --am-rad-advs: var(--am-rad-inp); --am-fs-advs: var(--am-fs-inp); --am-h-advs: var(--am-h-inp); --am-padd-advs: 0 12px; width: 100%; &__wrapper { width: 100%; } // Size - default / medium / small / mini / micro &--default { --am-h-advs: 40px; } &--medium { --am-h-advs: 36px; } &--small { --am-h-advs: 32px; } &--mini { --am-h-advs: 28px; } &--micro { --am-h-advs: 24px; } // Disabled &--disabled { --am-c-advs-bgr: var(--am-c-advs-text-op10); --am-c-advs-text: var(--am-c-advs-text-op60); } // Element visual presentation .el-input { border: none; border-radius: 4px; box-shadow: 0 2px 2px var(--am-c-advs-shadow); &.is-focus { // prevent hover color to be applied .el-input__wrapper { --am-c-advs-border: var(--am-c-primary); } } &.el-input--prefix { --am-padd-advs: 0 8px; } // Visual presentation of input &__wrapper { display: inline-flex; align-items: center; gap: 0 6px; background-image: none; background-color: var(--am-c-advs-bgr); border: none; border-radius: var(--am-rad-advs); box-shadow: 0 0 0 1px var(--am-c-advs-border); padding: var(--am-padd-advs); height: var(--am-h-advs); transition: 0.3s; &:hover { --am-c-advs-border: var(--am-c-advs-text-op40); } &:focus, &:active &.is-focus { --am-c-advs-border: var(--am-c-primary); } } &__inner { height: 24px; font-size: var(--am-fs-advs); font-weight: 400; line-height: 1.6; color: var(--am-c-advs-text); background-color: transparent; border: none; border-radius: var(--am-rad-advs); padding: 0; width: 100%; &::-webkit-input-placeholder { /* Chrome/Opera/Safari */ color: var(--am-c-advs-placeholder); } &::-moz-placeholder { /* Firefox 19+ */ color: var(--am-c-advs-placeholder); } &:-ms-input-placeholder { /* IE 10+ */ color: var(--am-c-advs-placeholder); } &:-moz-placeholder { /* Firefox 18- */ color: var(--am-c-advs-placeholder); } &:focus { border: none; box-shadow: none; } } &__suffix { .el-input__validateIcon { border: none; } .el-icon { font-family: 'amelia-icons'; font-size: 18px; color: var(--am-c-advs-text); &.icon-arrow-down { &:before { font-family: 'amelia-icons' !important; font-size: 18px; content: $am-icon-arrow-down; } svg { display: none; } } &.icon-circle-close { &:before { font-family: 'amelia-icons' !important; font-size: 18px; content: $am-icon-close; } svg { display: none; } } } } &__prefix { [class^='am-icon'] { font-size: 24px; line-height: 1; color: var(--am-c-advs-text); } } } &.am-rtl { .el-input { &__suffix { right: unset; left: 12px; } } } } } // public .amelia-v2-booking #amelia-container { @include am-adv-select-block; } // admin #amelia-app-backend-new { @include am-adv-select-block; } // Adv Select Dropdown - Popper .am-adv-select__popper { --am-c-advs-item-bgr: var(--am-c-drop-bgr); --am-c-advs-item-label: var(--am-c-main-text); --am-c-advs-item-price: var(--am-c-primary); --am-c-advs-item-selected: var(--am-c-primary); --am-h-advs-item-heading: 26px; --am-fs-advs-item-heading: 12px; max-width: 454px; width: 100%; z-index: 9999999999 !important; &.el-cascader__dropdown.el-popper[role=tooltip] { background-color: transparent; border-color: var(--am-c-advs-item-border); overflow: hidden; } * { font-family: var(--am-font-family); border-radius: unset; box-sizing: border-box; } // Adv Select Dropdown Category Name &-heading { position: absolute; top: 0; left: 0; display: flex; align-items: center; width: 100%; height: var(--am-h-advs-item-heading); font-size: var(--am-fs-advs-item-heading); font-weight: 700; font-style: normal; line-height: 1.5; color: var(--am-c-advs-item-heading-op65); background-color: var(--am-c-advs-item-bgr); padding-left: 8px; } .el-cascader { // Panel - dropdown &-panel { display: flex; background-color: var(--am-c-advs-item-bgr); max-width: 454px; width: 100%; } // Panel sides (columns) - Menu &-menu { width: 100%; min-width: 170px; // First column &:nth-child(1) { padding-top: 26px; flex-shrink: 2; border-color: var(--am-c-advs-item-border-op10); } // Second column &:nth-child(2) { padding-top: 26px; flex-shrink: 1; } &:last-child { .el-cascader-node { padding: 0; } } .el-scrollbar__bar.is-vertical { display: block !important; top: var(--am-h-advs-item-heading); padding-top: 6px; .el-scrollbar__thumb { background: var(--am-c-advs-item-label); opacity: 0.3; } } } &-node { height: unset; padding: 0; &:not(.is-disabled):hover, &:not(.is-disabled):focus { background-color: var(--am-c-advs-item-bgr-op10); } &.in-active-path { .am-adv-select__item-label { color: var(--am-c-advs-item-selected); } } &__label { display: flex; align-items: center; justify-content: space-between; padding: 4px 16px 4px 8px; } i { display: none; } } &__suggestion-list { background-color: var(--am-c-advs-item-bgr); color: var(--am-c-advs-item-label-op65); } } .am-adv-select { &__item { width: 100%; display: flex; align-items: center; justify-content: space-between; &-checked { .am-adv-select__item-label { color: var(--am-c-advs-item-selected); } } &-label { display: block; font-size: 14px; font-weight: 400; line-height: 1.43; color: var(--am-c-advs-item-label); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } &-quantity { font-size: 14px; font-weight: 400; line-height: 1.714; color: var(--am-c-advs-item-label-op40); } &-price { font-size: 14px; font-weight: 400; line-height: 1.714; color: var(--am-c-advs-item-price); } &-tax { display: inline-flex; font-size: 14px; font-weight: 400; line-height: 1; color: var(--am-c-advs-item-price); background-color: var(--am-c-advs-item-price-op10); border-radius: 10px; padding: 3px 8px; } } } .el-popper__arrow { display: none; } // Mobile &-mobile { width: calc(100% - 20px); .el-cascader { // Panel - dropdown &-panel { height: min-content; max-width: 100%; width: 100%; display: flex; flex-direction: column; .am-adv-select__popper-heading { height: var(--am-h-advs-item-heading); font-size: var(--am-fs-advs-item-heading); box-shadow: 0 2px 2px var(--am-c-advs-shadow); } } &-menu { min-height: 160px; &:first-child:not(:only-child) { border-bottom: 1px solid var(--am-c-inp-border); } &__wrap { height: min-content; max-height: 160px; overflow-y: scroll; } } } } } </style>
Save
Back