condition-number-input.tsx 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. import {
  2. memo,
  3. useCallback,
  4. useState,
  5. } from 'react'
  6. import { useTranslation } from 'react-i18next'
  7. import { RiArrowDownSLine } from '@remixicon/react'
  8. import { capitalize } from 'lodash-es'
  9. import { useBoolean } from 'ahooks'
  10. import { VarType as NumberVarType } from '../../tool/types'
  11. import VariableTag from '../../_base/components/variable-tag'
  12. import {
  13. PortalToFollowElem,
  14. PortalToFollowElemContent,
  15. PortalToFollowElemTrigger,
  16. } from '@/app/components/base/portal-to-follow-elem'
  17. import Button from '@/app/components/base/button'
  18. import cn from '@/utils/classnames'
  19. import VarReferenceVars from '@/app/components/workflow/nodes/_base/components/variable/var-reference-vars'
  20. import type {
  21. NodeOutPutVar,
  22. ValueSelector,
  23. } from '@/app/components/workflow/types'
  24. import { VarType } from '@/app/components/workflow/types'
  25. import { variableTransformer } from '@/app/components/workflow/utils'
  26. import { Variable02 } from '@/app/components/base/icons/src/vender/solid/development'
  27. const options = [
  28. NumberVarType.variable,
  29. NumberVarType.constant,
  30. ]
  31. type ConditionNumberInputProps = {
  32. numberVarType?: NumberVarType
  33. onNumberVarTypeChange: (v: NumberVarType) => void
  34. value: string
  35. onValueChange: (v: string) => void
  36. variables: NodeOutPutVar[]
  37. isShort?: boolean
  38. unit?: string
  39. }
  40. const ConditionNumberInput = ({
  41. numberVarType = NumberVarType.constant,
  42. onNumberVarTypeChange,
  43. value,
  44. onValueChange,
  45. variables,
  46. isShort,
  47. unit,
  48. }: ConditionNumberInputProps) => {
  49. const { t } = useTranslation()
  50. const [numberVarTypeVisible, setNumberVarTypeVisible] = useState(false)
  51. const [variableSelectorVisible, setVariableSelectorVisible] = useState(false)
  52. const [isFocus, {
  53. setTrue: setFocus,
  54. setFalse: setBlur,
  55. }] = useBoolean()
  56. const handleSelectVariable = useCallback((valueSelector: ValueSelector) => {
  57. onValueChange(variableTransformer(valueSelector) as string)
  58. setVariableSelectorVisible(false)
  59. }, [onValueChange])
  60. return (
  61. <div className='flex items-center cursor-pointer'>
  62. <PortalToFollowElem
  63. open={numberVarTypeVisible}
  64. onOpenChange={setNumberVarTypeVisible}
  65. placement='bottom-start'
  66. offset={{ mainAxis: 2, crossAxis: 0 }}
  67. >
  68. <PortalToFollowElemTrigger onClick={() => setNumberVarTypeVisible(v => !v)}>
  69. <Button
  70. className='shrink-0'
  71. variant='ghost'
  72. size='small'
  73. >
  74. {capitalize(numberVarType)}
  75. <RiArrowDownSLine className='ml-[1px] w-3.5 h-3.5' />
  76. </Button>
  77. </PortalToFollowElemTrigger>
  78. <PortalToFollowElemContent className='z-[1000]'>
  79. <div className='p-1 w-[112px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg'>
  80. {
  81. options.map(option => (
  82. <div
  83. key={option}
  84. className={cn(
  85. 'flex items-center px-3 h-7 rounded-md hover:bg-state-base-hover cursor-pointer',
  86. 'text-[13px] font-medium text-text-secondary',
  87. numberVarType === option && 'bg-state-base-hover',
  88. )}
  89. onClick={() => {
  90. onNumberVarTypeChange(option)
  91. setNumberVarTypeVisible(false)
  92. }}
  93. >
  94. {capitalize(option)}
  95. </div>
  96. ))
  97. }
  98. </div>
  99. </PortalToFollowElemContent>
  100. </PortalToFollowElem>
  101. <div className='mx-1 w-[1px] h-4 bg-divider-regular'></div>
  102. <div className='grow w-0 ml-0.5'>
  103. {
  104. numberVarType === NumberVarType.variable && (
  105. <PortalToFollowElem
  106. open={variableSelectorVisible}
  107. onOpenChange={setVariableSelectorVisible}
  108. placement='bottom-start'
  109. offset={{ mainAxis: 2, crossAxis: 0 }}
  110. >
  111. <PortalToFollowElemTrigger
  112. className='w-full'
  113. onClick={() => setVariableSelectorVisible(v => !v)}>
  114. {
  115. value && (
  116. <VariableTag
  117. valueSelector={variableTransformer(value) as string[]}
  118. varType={VarType.number}
  119. isShort={isShort}
  120. />
  121. )
  122. }
  123. {
  124. !value && (
  125. <div className='flex items-center p-1 h-6 text-components-input-text-placeholder text-[13px]'>
  126. <Variable02 className='shrink-0 mr-1 w-4 h-4' />
  127. <div className='w-0 grow truncate'>{t('workflow.nodes.ifElse.selectVariable')}</div>
  128. </div>
  129. )
  130. }
  131. </PortalToFollowElemTrigger>
  132. <PortalToFollowElemContent className='z-[1000]'>
  133. <div className={cn('w-[296px] pt-1 bg-components-panel-bg-blur rounded-lg border-[0.5px] border-components-panel-border shadow-lg', isShort && 'w-[200px]')}>
  134. <VarReferenceVars
  135. vars={variables}
  136. onChange={handleSelectVariable}
  137. />
  138. </div>
  139. </PortalToFollowElemContent>
  140. </PortalToFollowElem>
  141. )
  142. }
  143. {
  144. numberVarType === NumberVarType.constant && (
  145. <div className=' relative'>
  146. <input
  147. className={cn('block w-full px-2 text-[13px] text-components-input-text-filled placeholder:text-components-input-text-placeholder outline-none appearance-none bg-transparent', unit && 'pr-6')}
  148. type='number'
  149. value={value}
  150. onChange={e => onValueChange(e.target.value)}
  151. placeholder={t('workflow.nodes.ifElse.enterValue') || ''}
  152. onFocus={setFocus}
  153. onBlur={setBlur}
  154. />
  155. {!isFocus && unit && <div className='absolute right-2 top-[50%] translate-y-[-50%] text-text-tertiary system-sm-regular'>{unit}</div>}
  156. </div>
  157. )
  158. }
  159. </div>
  160. </div>
  161. )
  162. }
  163. export default memo(ConditionNumberInput)