mirror of
https://git.mirrors.martin98.com/https://github.com/langgenius/dify.git
synced 2025-08-18 07:25:54 +08:00
feat: implement AutoWidthInput component for dynamic input sizing in visual editor
This commit is contained in:
parent
d29b3292f0
commit
e250f5aab2
@ -18,8 +18,8 @@ const Card: FC<CardProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-col py-0.5'>
|
<div className='flex flex-col py-0.5'>
|
||||||
<div className='flex items-center gap-x-1 p-0.5 pl-1'>
|
<div className='flex h-6 items-center gap-x-1 pl-1 pr-0.5'>
|
||||||
<div className='system-sm-semibold truncate px-1 py-0.5 text-text-primary'>
|
<div className='system-sm-semibold truncate border border-transparent px-1 py-px text-text-primary'>
|
||||||
{name}
|
{name}
|
||||||
</div>
|
</div>
|
||||||
<div className='system-xs-medium px-1 py-0.5 text-text-tertiary'>
|
<div className='system-xs-medium px-1 py-0.5 text-text-tertiary'>
|
||||||
|
@ -0,0 +1,81 @@
|
|||||||
|
import React, { useEffect, useState } from 'react'
|
||||||
|
import type { FC } from 'react'
|
||||||
|
import cn from '@/utils/classnames'
|
||||||
|
|
||||||
|
type AutoWidthInputProps = {
|
||||||
|
value: string
|
||||||
|
placeholder: string
|
||||||
|
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void
|
||||||
|
onBlur: () => void
|
||||||
|
minWidth?: number
|
||||||
|
maxWidth?: number
|
||||||
|
} & Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange'>
|
||||||
|
|
||||||
|
const AutoWidthInput: FC<AutoWidthInputProps> = ({
|
||||||
|
value,
|
||||||
|
placeholder,
|
||||||
|
onChange,
|
||||||
|
onBlur,
|
||||||
|
minWidth = 60,
|
||||||
|
maxWidth = 300,
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
}) => {
|
||||||
|
const [width, setWidth] = useState(minWidth)
|
||||||
|
const textRef = React.useRef<HTMLSpanElement>(null)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (textRef.current) {
|
||||||
|
textRef.current.textContent = value || placeholder
|
||||||
|
const textWidth = textRef.current.offsetWidth
|
||||||
|
const newWidth = Math.max(minWidth, Math.min(textWidth + 16, maxWidth))
|
||||||
|
if (width !== newWidth)
|
||||||
|
setWidth(newWidth)
|
||||||
|
}
|
||||||
|
}, [value, placeholder, minWidth, maxWidth, width])
|
||||||
|
|
||||||
|
// Handle Enter key
|
||||||
|
const handleKeyUp = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||||
|
if (e.key === 'Enter' && e.currentTarget.blur)
|
||||||
|
e.currentTarget.blur()
|
||||||
|
if (props.onKeyUp)
|
||||||
|
props.onKeyUp(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='relative inline-flex items-center'>
|
||||||
|
{/* Hidden measurement span */}
|
||||||
|
<span
|
||||||
|
ref={textRef}
|
||||||
|
className='system-sm-semibold invisible absolute left-0 top-0 -z-10 whitespace-pre px-1'
|
||||||
|
aria-hidden="true"
|
||||||
|
>
|
||||||
|
{value || placeholder}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{/* Actual input element */}
|
||||||
|
<input
|
||||||
|
value={value}
|
||||||
|
className={cn(
|
||||||
|
'system-sm-semibold placeholder:system-sm-semibold h-5 rounded-[5px] border border-transparent px-1',
|
||||||
|
'py-px text-text-primary caret-[#295EFF] shadow-shadow-shadow-3 outline-none',
|
||||||
|
'placeholder:text-text-placeholder hover:bg-state-base-hover focus:border-components-input-border-active focus:bg-components-input-bg-active focus:shadow-xs',
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
style={{
|
||||||
|
width: `${width}px`,
|
||||||
|
minWidth: `${minWidth}px`,
|
||||||
|
maxWidth: `${maxWidth}px`,
|
||||||
|
transition: 'width 100ms ease-out',
|
||||||
|
}}
|
||||||
|
placeholder={placeholder}
|
||||||
|
onChange={onChange}
|
||||||
|
onBlur={onBlur}
|
||||||
|
onKeyUp={handleKeyUp}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default React.memo(AutoWidthInput)
|
@ -14,6 +14,7 @@ import { useVisualEditorStore } from '../store'
|
|||||||
import { useMittContext } from '../context'
|
import { useMittContext } from '../context'
|
||||||
import { useUnmount } from 'ahooks'
|
import { useUnmount } from 'ahooks'
|
||||||
import { JSON_SCHEMA_MAX_DEPTH } from '@/config'
|
import { JSON_SCHEMA_MAX_DEPTH } from '@/config'
|
||||||
|
import AutoWidthInput from './auto-width-input'
|
||||||
|
|
||||||
export type EditData = {
|
export type EditData = {
|
||||||
name: string
|
name: string
|
||||||
@ -192,17 +193,15 @@ const EditCard: FC<EditCardProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-col rounded-lg bg-components-panel-bg py-0.5 shadow-sm shadow-shadow-shadow-4'>
|
<div className='flex flex-col rounded-lg bg-components-panel-bg py-0.5 shadow-sm shadow-shadow-shadow-4'>
|
||||||
<div className='flex items-center pl-1 pr-0.5'>
|
<div className='flex h-6 items-center pl-1 pr-0.5'>
|
||||||
<div className='flex grow items-center gap-x-1'>
|
<div className='flex grow items-center gap-x-1'>
|
||||||
<input
|
<AutoWidthInput
|
||||||
value={currentFields.name}
|
value={currentFields.name}
|
||||||
className='system-sm-semibold placeholder:system-sm-semibold h-5 max-w-20 rounded-[5px] border border-transparent px-1
|
|
||||||
py-0.5 text-text-primary caret-[#295EFF] shadow-shadow-shadow-3 outline-none
|
|
||||||
placeholder:text-text-placeholder hover:bg-state-base-hover focus:border-components-input-border-active focus:bg-components-input-bg-active focus:shadow-xs'
|
|
||||||
placeholder={t('workflow.nodes.llm.jsonSchema.fieldNamePlaceholder')}
|
placeholder={t('workflow.nodes.llm.jsonSchema.fieldNamePlaceholder')}
|
||||||
|
minWidth={80}
|
||||||
|
maxWidth={300}
|
||||||
onChange={handlePropertyNameChange}
|
onChange={handlePropertyNameChange}
|
||||||
onBlur={handlePropertyNameBlur}
|
onBlur={handlePropertyNameBlur}
|
||||||
onKeyUp={e => e.key === 'Enter' && e.currentTarget.blur()}
|
|
||||||
/>
|
/>
|
||||||
<TypeSelector
|
<TypeSelector
|
||||||
currentValue={currentFields.type}
|
currentValue={currentFields.type}
|
||||||
|
@ -48,9 +48,6 @@ export default function Page() {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
completed: {
|
|
||||||
type: Type.boolean,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
required: [
|
required: [
|
||||||
'userId',
|
'userId',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user