{"version":3,"file":"ToggleOption-b70mFFJc.js","sources":["../../../app/javascript/src/components/Theme/SearchableSelect.vue","../../../app/javascript/src/modules/Explore/ToggleInput.vue","../../../app/javascript/src/modules/LiteCMS/Common/ToggleOption.vue"],"sourcesContent":["<template>\n <div ref=\"wrapperEl\" class=\"theme-select\">\n <div class=\"theme-select__body\">\n <div class=\"select\">\n <div class=\"form-control form-input current\"\n :class=\"{ placeholder: showPlaceholder }\"\n @click=\"dropdown = !dropdown\"\n v-html=\"displayValue\"\n ></div>\n\n <div class=\"dropdown\" v-show=\"dropdown\">\n <div class=\"search\" v-if=\"searchable\">\n <input class=\"form-input\"\n ref=\"searchInput\"\n type=\"search\"\n v-model=\"search\"\n @keydown.up.prevent=\"highlightPrev()\"\n @keydown.down.prevent=\"highlightNext()\"\n @keydown.tab.prevent=\"highlightNext()\"\n @keydown.enter.prevent=\"selectHighlightedOption()\"\n />\n <i class=\"icon icon-search\" />\n </div>\n <div class=\"options\" v-if=\"filteredOptions.length > 0\">\n <div class=\"option\"\n :class=\"{ highlight: highlightIndex === i }\"\n v-for=\"(option, i) in filteredOptions\" :key=\"i\"\n @mouseover=\"highlightIndex = i\"\n @click=\"selectOption(option)\"\n >\n {{ option.label }}\n </div>\n </div>\n </div>\n </div>\n <i class=\"icon icon-arrow-down-1\" />\n </div>\n </div>\n</template>\n\n<script setup>\nimport { computed, nextTick, ref, watch } from \"vue\";\nimport { onClickOutside } from \"@vueuse/core\";\nimport Fuse from 'fuse.js'\n\nconst props = defineProps({\n placeholder: String,\n value: { type: [String, Number] },\n options: Array, // [{value, label}, ...]\n searchable: {\n type: Boolean,\n default: true\n }\n});\nconst emit = defineEmits(['select']);\n\nconst fuse = new Fuse(props.options, { keys: ['label', 'value'] });\n\nconst search = ref('');\nconst dropdown = ref(false);\nconst highlightIndex = ref(null);\nconst searchInput = ref(null);\nconst wrapperEl = ref();\n\nconst filteredOptions = computed(() => {\n return search.value ? fuse.search(search.value).map(r => r.item) : props.options;\n});\n\nconst showPlaceholder = computed(() => props.placeholder && !props.value);\n\nconst displayValue = computed(() => {\n if (showPlaceholder.value) {\n return props.placeholder;\n }\n const matched = props.options.find(opt => opt.value === props.value);\n return matched ? matched.label : ' ';\n});\n\nwatch(dropdown, (open) => nextTick(() => {\n if (open) searchInput.value?.focus();\n}));\n\nwatch(filteredOptions, (rows) => {\n highlightIndex.value = rows.length > 0 ? 0 : null;\n showHighlightedOption();\n});\n\nonClickOutside(wrapperEl, () => dropdown.value = false);\n\nfunction highlightPrev() {\n if (highlightIndex.value === null) {\n highlightIndex.value = filteredOptions.value.length - 1;\n }\n else if (highlightIndex.value > 0) {\n highlightIndex.value -= 1;\n }\n showHighlightedOption();\n}\n\nfunction highlightNext() {\n if (highlightIndex.value === null) {\n highlightIndex.value = 0;\n }\n else if (highlightIndex.value < (filteredOptions.value.length - 1)) {\n highlightIndex.value += 1;\n }\n showHighlightedOption();\n}\n\nfunction selectOption(option) {\n emit('select', option.value);\n dropdown.value = false;\n search.value = '';\n}\n\nfunction selectHighlightedOption() {\n const option = filteredOptions.value[highlightIndex.value];\n if (option) selectOption(option);\n}\n\nfunction showHighlightedOption() {\n if (highlightIndex.value !== null) {\n nextTick(() => document.querySelector('.option.highlight').scrollIntoViewIfNeeded(false));\n }\n}\n</script>\n\n<style lang=\"scss\" scoped>\n$search-icon-size: 16px;\n\n.theme-select__body {\n position: relative;\n line-height: 1.15;\n display: flex;\n align-items: center;\n}\n\n.theme-select .icon {\n position: absolute;\n right: $spacing-5;\n color: $gray;\n pointer-events: none;\n}\n\n.select {\n flex: 1;\n cursor: pointer;\n position: relative;\n\n .placeholder {\n color: $gray;\n }\n\n .dropdown {\n background: $white;\n position: absolute;\n z-index: 100;\n left: 0;\n right: auto;\n min-width: 100%;\n top: calc(100% + $spacing-1);\n border: 1px solid $gray-lighter;\n border-radius: $rounded;\n max-height: 280px;\n @include flex-column;\n flex-shrink: 0;\n\n @media (max-width: $breakpoint-m) {\n max-height: 240px;\n }\n\n .options {\n flex: 1;\n padding: $spacing-3;\n overflow-y: auto;\n scrollbar-color: $gray $white;\n\n .option {\n border-radius: $rounded;\n padding: $spacing-2;\n line-height: $leading-snug;\n cursor: pointer;\n white-space: nowrap;\n\n &.highlight {\n background: $brand-tertiary-light;\n }\n }\n }\n\n .search {\n position: relative;\n margin: $spacing-3 $spacing-3 $spacing-1;\n .icon {\n position: absolute;\n left: $spacing-5;\n height: $search-icon-size;\n width: $search-icon-size;\n top: 15px;\n }\n input {\n padding-left: calc($spacing-5 + $search-icon-size + 10px);\n }\n }\n }\n}\n</style>\n","<template>\n <div class=\"toggle-input\" :class=\"{'toggle-input_disabled': disabled}\">\n <label class=\"toggle-input__switch\">\n <input type=\"checkbox\" @change=\"change\" v-bind=\"$attrs\" :disabled=\"disabled\">\n <span class=\"toggle-input__slider\"/>\n </label>\n </div>\n</template>\n\n<script setup>\ndefineProps({\n disabled: { type: Boolean, default: false }\n});\nconst emit = defineEmits(['change']);\n\nfunction change(evt) {\n emit('change', evt.target.checked);\n}\n</script>\n\n<style lang=\"scss\" scoped>\n$slider-size: 20px;\n$slider-margin: 2px; /* (switchHeight - sliderSize) / 2 */\n$switch-height: 24px;\n$switch-width: 44px; /* (switchHeight - sliderMargin) * 2 */\n\n.toggle-input {\n display: inline-block;\n\n input:checked + .toggle-input__slider {\n background-color: $brand-tertiary;\n }\n\n input:focus + .toggle-input__slider {\n box-shadow: 0 0 1px $brand-tertiary;\n }\n\n input:checked + .toggle-input__slider:before {\n transform: translateX($slider-size);\n }\n\n &_disabled {\n input:checked + .toggle-input__slider {\n background-color: $gray-lighter;\n }\n }\n}\n\n.toggle-input__switch {\n position: relative;\n display: inline-block;\n width: $switch-width;\n height: $switch-height;\n}\n\n.toggle-input__switch input {\n opacity: 0;\n width: 0;\n height: 0;\n}\n\n.toggle-input__slider {\n position: absolute;\n cursor: pointer;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: $gray-lighter;\n transition: .4s;\n border-radius: $switch-height;\n}\n\n.toggle-input__slider:before {\n position: absolute;\n content: '';\n height: $slider-size;\n width: $slider-size;\n left: $slider-margin;\n bottom: $slider-margin;\n background-color: white;\n transition: .4s;\n border-radius: 50%;\n}\n</style>\n","<template>\n <div class=\"toggle-option\">\n <div :class=\"{'toggle-option_disabled': disabled}\">\n <slot/>\n </div>\n\n <ToggleInput :checked=\"model\" @change=\"model = $event\" v-bind=\"$attrs\" :disabled=\"disabled\" />\n </div>\n</template>\n\n<script setup>\nimport ToggleInput from \"@/modules/Explore/ToggleInput.vue\";\n\ndefineProps({\n disabled: { type: Boolean, default: false }\n});\n\nconst model = defineModel();\n</script>\n\n<style lang=\"scss\" scoped>\n@import \"app/assets/stylesheets/litecms\";\n\n$slider-size: 26px;\n$slider-margin: 2px; /* (switchHeight - sliderSize) / 2 */\n$switch-height: 30px;\n$switch-width: 50px; /* (switchHeight - sliderMargin) * 2 */\n\n.toggle-option {\n display: flex;\n justify-content: space-between;\n align-items: center;\n gap: $spacing-6;\n}\n\n.toggle-option :deep(.toggle-input) {\n input:checked + .toggle-input__slider:before {\n transform: translateX(20px);\n }\n\n .toggle-input__switch {\n width: $switch-width;\n height: $switch-height;\n }\n\n .toggle-input__slider {\n border-radius: $switch-height;\n }\n\n .toggle-input__slider:before {\n height: $slider-size;\n width: $slider-size;\n left: $slider-margin;\n bottom: $slider-margin;\n box-shadow: 0 3px 1px 0 #0000000F, 0 3px 8px 0 #00000026;\n }\n}\n\n.toggle-option_disabled {\n color: $gray;\n}\n</style>\n"],"names":["props","__props","emit","__emit","fuse","Fuse","search","ref","dropdown","highlightIndex","searchInput","wrapperEl","filteredOptions","computed","r","showPlaceholder","displayValue","matched","opt","watch","open","nextTick","_a","rows","showHighlightedOption","onClickOutside","highlightPrev","highlightNext","selectOption","option","selectHighlightedOption","change","evt","model","_useModel"],"mappings":"uoBA6CA,MAAMA,EAAQC,EASRC,EAAOC,EAEPC,EAAO,IAAIC,EAAKL,EAAM,QAAS,CAAE,KAAM,CAAC,QAAS,OAAO,EAAG,EAE3DM,EAASC,EAAI,EAAE,EACfC,EAAWD,EAAI,EAAK,EACpBE,EAAiBF,EAAI,IAAI,EACzBG,EAAcH,EAAI,IAAI,EACtBI,EAAYJ,EAAK,EAEjBK,EAAkBC,EAAS,IACxBP,EAAO,MAAQF,EAAK,OAAOE,EAAO,KAAK,EAAE,IAAIQ,GAAKA,EAAE,IAAI,EAAId,EAAM,OAC1E,EAEKe,EAAkBF,EAAS,IAAMb,EAAM,aAAe,CAACA,EAAM,KAAK,EAElEgB,EAAeH,EAAS,IAAM,CAClC,GAAIE,EAAgB,MAClB,OAAOf,EAAM,YAEf,MAAMiB,EAAUjB,EAAM,QAAQ,KAAKkB,GAAOA,EAAI,QAAUlB,EAAM,KAAK,EACnE,OAAOiB,EAAUA,EAAQ,MAAQ,QACnC,CAAC,EAEDE,EAAMX,EAAWY,GAASC,EAAS,IAAM,OACnCD,KAAME,EAAAZ,EAAY,QAAZ,MAAAY,EAAmB,QAC/B,CAAC,CAAC,EAEFH,EAAMP,EAAkBW,GAAS,CAC/Bd,EAAe,MAAQc,EAAK,OAAS,EAAI,EAAI,KAC7CC,EAAuB,CACzB,CAAC,EAEDC,EAAed,EAAW,IAAMH,EAAS,MAAQ,EAAK,EAEtD,SAASkB,GAAgB,CACnBjB,EAAe,QAAU,KAC3BA,EAAe,MAAQG,EAAgB,MAAM,OAAS,EAE/CH,EAAe,MAAQ,IAC9BA,EAAe,OAAS,GAE1Be,EAAuB,CACzB,CAEA,SAASG,GAAgB,CACnBlB,EAAe,QAAU,KAC3BA,EAAe,MAAQ,EAEhBA,EAAe,MAASG,EAAgB,MAAM,OAAS,IAC9DH,EAAe,OAAS,GAE1Be,EAAuB,CACzB,CAEA,SAASI,EAAaC,EAAQ,CAC5B3B,EAAK,SAAU2B,EAAO,KAAK,EAC3BrB,EAAS,MAAQ,GACjBF,EAAO,MAAQ,EACjB,CAEA,SAASwB,GAA0B,CACjC,MAAMD,EAASjB,EAAgB,MAAMH,EAAe,KAAK,EACrDoB,GAAQD,EAAaC,CAAM,CACjC,CAEA,SAASL,GAAwB,CAC3Bf,EAAe,QAAU,MAC3BY,EAAS,IAAM,SAAS,cAAc,mBAAmB,EAAE,uBAAuB,EAAK,CAAC,CAE5F,krCC/GA,MAAMnB,EAAOC,EAEb,SAAS4B,EAAOC,EAAK,CACnB9B,EAAK,SAAU8B,EAAI,OAAO,OAAO,CACnC,4dCAA,MAAMC,EAAQC,gBAAY"}