OptionsFilter.vue 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. <template>
  2. <div class="flex min-h-56.5 flex-col justify-between gap-2">
  3. <Listbox
  4. v-model="model"
  5. :options="options"
  6. multiple
  7. scrollHeight="12rem"
  8. @change="filterCallback"
  9. >
  10. <!--suppress VueUnrecognizedSlot -->
  11. <template #option="{ option, selected, index }">
  12. <div
  13. :id="`filter_${index}`"
  14. class="flex w-full flex-row items-center gap-1"
  15. :class="
  16. !isFilteredOption(option) &&
  17. 'text-surface-400! dark:text-surface-500!'
  18. "
  19. >
  20. <div class="min-w-[0.875em]">
  21. <Icon
  22. v-if="selected"
  23. name="ph:check-bold"
  24. size="0.875em"
  25. />
  26. </div>
  27. <div class="truncate">
  28. {{ option }}
  29. </div>
  30. </div>
  31. </template>
  32. </Listbox>
  33. <Button
  34. class="py-0.5!"
  35. variant="outlined"
  36. size="small"
  37. fluid
  38. :disabled="!hasFilter()"
  39. @click="resetFilter"
  40. >
  41. Clear
  42. </Button>
  43. </div>
  44. </template>
  45. <script setup>
  46. const model = defineModel()
  47. const props = defineProps({
  48. options: {
  49. type: Array,
  50. required: true
  51. },
  52. filteredOptions: {
  53. type: Array,
  54. required: true
  55. },
  56. filterCallback: {
  57. type: Function,
  58. required: true
  59. },
  60. hasFilter: {
  61. type: Function,
  62. required: true
  63. },
  64. resetFilter: {
  65. type: Function,
  66. required: true
  67. }
  68. })
  69. function isFilteredOption(option) {
  70. return _includes(props.filteredOptions, option)
  71. }
  72. </script>
  73. <style scoped></style>