index.ts 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. // Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. import { radio as radioDefinition } from '@formkit/inputs'
  3. import { has } from '@formkit/utils'
  4. import initializeFieldDefinition from '#shared/form/core/initializeFieldDefinition.ts'
  5. import formUpdaterTrigger from '#shared/form/features/formUpdaterTrigger.ts'
  6. import extendSchemaDefinition from '#shared/form/utils/extendSchemaDefinition.ts'
  7. import type { FormKitNode } from '@formkit/core'
  8. const addOptionCheckedDataAttribute = (node: FormKitNode) => {
  9. extendSchemaDefinition(node, 'wrapper', {
  10. attrs: {
  11. 'data-is-checked': {
  12. if: '$fns.isChecked($option.value)',
  13. then: 'true',
  14. else: undefined,
  15. },
  16. 'data-test-id': 'radio-label',
  17. },
  18. })
  19. }
  20. const addSubmitEvent = (node: FormKitNode) => {
  21. if (typeof node.props.onSubmit !== 'function') return
  22. extendSchemaDefinition(node, 'wrapper', {
  23. attrs: {
  24. onKeypress: (event: KeyboardEvent) => {
  25. if (event.key === 'Enter') {
  26. event.preventDefault()
  27. node.props.onSubmit.call(
  28. null,
  29. new SubmitEvent('submit', {
  30. submitter: event.target as HTMLElement,
  31. }),
  32. )
  33. }
  34. },
  35. },
  36. })
  37. }
  38. const addIconLabel = (node: FormKitNode) => {
  39. extendSchemaDefinition(node, 'label', {
  40. attrs: {
  41. id: null,
  42. },
  43. children: [
  44. {
  45. if: '$option.icon',
  46. $cmp: 'CommonIcon',
  47. props: {
  48. class: 'inline-flex ltr:mr-3 rtl:ml-3',
  49. name: '$option.icon',
  50. size: 'base',
  51. },
  52. },
  53. '$option.label',
  54. ],
  55. })
  56. }
  57. const handleButtonMode = (node: FormKitNode) => {
  58. const { props } = node
  59. node.addProps(['buttons'])
  60. const setClasses = (buttons: boolean) => {
  61. if (buttons) {
  62. props.optionsClass = 'flex flex-col grow space-y-2'
  63. props.optionClass = 'formkit-disabled:opacity-30'
  64. // this is needed to not show "required" label on buttons
  65. props.labelClass = '$reset'
  66. props.wrapperClass =
  67. 'items-center justify-center py-2 px-4 w-full h-14 text-lg font-normal text-white bg-gray-600 rounded-xl select-none formkit-is-checked:bg-white formkit-is-checked:text-black formkit-is-checked:font-semibold'
  68. props.inputClass = '$reset sr-only'
  69. props.decoratorClass = 'hidden'
  70. } else {
  71. props.inputClass =
  72. 'h-4 w-4 border-[1.5px] border-white rounded-full bg-transparent focus:border-blue focus:bg-blue-highlight checked:focus:color-blue checked:bg-blue checked:border-blue checked:focus:bg-blue checked:hover:bg-blue'
  73. }
  74. }
  75. node.on('created', () => {
  76. if (!has(props, 'buttons')) {
  77. props.buttons = false
  78. }
  79. setClasses(props.buttons)
  80. node.on('prop:buttons', ({ payload }) => {
  81. setClasses(payload)
  82. })
  83. })
  84. }
  85. initializeFieldDefinition(radioDefinition, {
  86. features: [
  87. addOptionCheckedDataAttribute,
  88. addSubmitEvent,
  89. handleButtonMode,
  90. addIconLabel,
  91. formUpdaterTrigger(),
  92. ],
  93. })
  94. export default {
  95. fieldType: 'radio',
  96. definition: radioDefinition,
  97. }
  98. export type { RadioOption } from './types.ts'