TableRow.vue 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. <!-- Copyright (C) 2012-2025 Zammad Foundation, https://zammad-foundation.org/ -->
  2. <script setup lang="ts">
  3. import { computed } from 'vue'
  4. import type { TableItem } from './types'
  5. export interface Props {
  6. item: TableItem
  7. onClickRow?: (tableItem: TableItem) => void
  8. isRowSelected?: boolean
  9. hasCheckbox?: boolean
  10. noAutoStriping?: boolean
  11. isStriped?: boolean
  12. }
  13. const props = defineProps<Props>()
  14. const emit = defineEmits<{
  15. 'click-row': [TableItem]
  16. }>()
  17. const rowId = 'selectable-table-row'
  18. const rowEventHandler = computed(() =>
  19. (props.onClickRow || props.hasCheckbox) && !props.item.disabled
  20. ? {
  21. attrs: {
  22. 'aria-describedby': rowId,
  23. tabindex: props.hasCheckbox ? -1 : 0,
  24. class:
  25. 'group focus-visible:outline-transparent cursor-pointer active:bg-blue-800 active:dark:bg-blue-800 focus-visible:bg-blue-800 focus-visible:dark:bg-blue-900 focus-within:text-white hover:bg-blue-600 dark:hover:bg-blue-900',
  26. },
  27. events: {
  28. click: () => {
  29. ;(document.activeElement as HTMLElement)?.blur()
  30. emit('click-row', props.item)
  31. },
  32. keydown: (event: KeyboardEvent) => {
  33. if (event.key !== 'Enter') return
  34. emit('click-row', props.item)
  35. },
  36. },
  37. }
  38. : { attrs: {}, events: {} },
  39. )
  40. const hasScreenReaderHelpText = computed(
  41. () => !!document?.getElementById(rowId),
  42. )
  43. </script>
  44. <template>
  45. <tr
  46. :class="{
  47. 'odd:bg-blue-200 odd:dark:bg-gray-700': !noAutoStriping,
  48. 'bg-blue-200 dark:bg-gray-700': isStriped === true,
  49. '!bg-blue-800': !hasCheckbox && isRowSelected,
  50. }"
  51. style="clip-path: xywh(0 0 100% 100% round 0.375rem)"
  52. data-test-id="table-row"
  53. v-bind="rowEventHandler.attrs"
  54. v-on="rowEventHandler.events"
  55. >
  56. <slot :is-row-selected="isRowSelected" />
  57. <template v-if="!hasScreenReaderHelpText">
  58. <Teleport to="body">
  59. <p
  60. v-if="rowEventHandler.attrs['aria-describedby']"
  61. :id="rowId"
  62. class="sr-only absolute"
  63. >
  64. {{ __('Select table row') }}
  65. </p>
  66. </Teleport>
  67. </template>
  68. </tr>
  69. </template>