Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 45 additions & 5 deletions packages/components/tag-input/TagInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React, {
forwardRef,
KeyboardEvent,
MouseEvent,
useEffect,
useImperativeHandle,
useMemo,
useRef,
Expand Down Expand Up @@ -58,6 +59,7 @@ const TagInput = forwardRef<InputRef, TagInputProps>((originalProps, ref) => {
onBlur,
} = props;
const readOnly = props.readOnly || props.readonly;
const isBreakLine = excessTagsDisplayType === 'break-line';

const [tInputValue, setTInputValue] = useControlled(props, 'inputValue', props.onInputChange);

Expand All @@ -70,6 +72,9 @@ const TagInput = forwardRef<InputRef, TagInputProps>((originalProps, ref) => {
targetClassNameRegExp: new RegExp(`^${prefix}-tag`),
},
});

const suffixWidthRef = useRef<number>(0);
const suffixIconWidthRef = useRef<number>(0);
const isCompositionRef = useRef(false);

const { scrollToRight, onWheel, scrollToRightOnEnter, scrollToLeftOnLeave, tagInputRef } = useTagScroll(props);
Expand All @@ -92,6 +97,42 @@ const TagInput = forwardRef<InputRef, TagInputProps>((originalProps, ref) => {

useImperativeHandle(ref as InputRef, () => ({ ...(tagInputRef.current || {}) }));

const updateSuffixWidth = (selector: string, cssVar: string, widthRef: React.MutableRefObject<number>) => {
const wrapperEl = tagInputRef.current?.currentElement as HTMLElement;
if (!wrapperEl) return;

const inputEl = wrapperEl.querySelector(`.${prefix}-input`) as HTMLElement;
if (!inputEl) return;

const targetEl = wrapperEl.querySelector(selector);
const width = targetEl ? targetEl.getBoundingClientRect().width : 0;
if (width !== widthRef.current) {
// eslint-disable-next-line no-param-reassign
widthRef.current = width;
if (width) {
inputEl.style.setProperty(cssVar, `${Math.ceil(width + 8)}px`);
Comment thread
uyarn marked this conversation as resolved.
} else {
inputEl.style.removeProperty(cssVar);
}
}
};

useEffect(() => {
if (!isBreakLine || !suffix) return;

// 避免 suffix 左侧 与 tag 重合
updateSuffixWidth(
`.${prefix}-input__suffix:not(.${prefix}-input__suffix-icon)`,
`--${prefix}-tag-input-suffix-width`,
suffixWidthRef,
);

// 确定 suffix 右侧到 input 边框的距离
updateSuffixWidth(`.${prefix}-input__suffix-icon`, `--${prefix}-tag-input-suffix-icon-width`, suffixIconWidthRef);

// eslint-disable-next-line react-hooks/exhaustive-deps
}, [excessTagsDisplayType, suffix, suffixIcon, showClearIcon, prefix, tagInputRef, isBreakLine]);

const onInputCompositionstart = (value: InputValue, context: { e: CompositionEvent<HTMLInputElement> }) => {
isCompositionRef.current = true;
inputProps?.onCompositionstart?.(value, context);
Expand All @@ -109,7 +150,7 @@ const TagInput = forwardRef<InputRef, TagInputProps>((originalProps, ref) => {
};

const onInnerClick = (context: { e: MouseEvent<HTMLDivElement> }) => {
if (!props.disabled && !props.readonly) {
if (!props.disabled && !readOnly) {
(tagInputRef.current as any)?.inputElement?.focus?.();
}
onClick?.(context);
Expand Down Expand Up @@ -155,11 +196,11 @@ const TagInput = forwardRef<InputRef, TagInputProps>((originalProps, ref) => {
const classes = [
NAME_CLASS,
{
[BREAK_LINE_CLASS]: excessTagsDisplayType === 'break-line',
[BREAK_LINE_CLASS]: isBreakLine,
[WITH_SUFFIX_ICON_CLASS]: !!suffixIconNode,
[`${prefix}-is-empty`]: isEmpty,
[`${prefix}-tag-input--with-tag`]: !isEmpty,
[`${prefix}-tag-input--max-rows`]: excessTagsDisplayType === 'break-line' && maxRows,
[`${prefix}-tag-input--max-rows`]: isBreakLine && maxRows,
[`${prefix}-tag-input--drag-sort`]: props.dragSort && !disabled && !readOnly,
},
props.className,
Expand Down Expand Up @@ -196,8 +237,7 @@ const TagInput = forwardRef<InputRef, TagInputProps>((originalProps, ref) => {
suffix={suffix}
prefixIcon={prefixIcon}
suffixIcon={suffixIconNode}
// showInput={!inputProps?.readOnly || !inputProps?.readonly || !tagValue || !tagValue?.length}
showInput={!inputProps?.readonly || !tagValue || !tagValue?.length}
showInput={!inputProps?.readOnly || !inputProps?.readonly || !tagValue || !tagValue?.length}
keepWrapperWidth={!autoWidth}
onPaste={onPaste}
onClick={onInnerClick}
Expand Down
6 changes: 3 additions & 3 deletions packages/components/tag-input/useTagScroll.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
* 当标签数量过多时,输入框显示不下,则需要滚动查看,以下为滚动逻辑
* 如果标签过多时的处理方式,是标签省略,则不需要此功能
*/

import { isFunction } from 'lodash-es';
import { useEffect, useRef, useState, WheelEvent } from 'react';
import { isFunction } from 'lodash-es';
import type { InputRef } from '../input';
import type { TdTagInputProps } from './type';

let mouseEnterTimer = null;
Expand All @@ -13,7 +13,7 @@ export default function useTagScroll(props: TdTagInputProps) {
const { excessTagsDisplayType = 'scroll', disabled } = props;
const readOnly = props.readOnly || props.readonly;

const tagInputRef = useRef<{ currentElement: HTMLDivElement }>(null);
const tagInputRef = useRef<InputRef>(null);

// 允许向右滚动的最大距离
const [scrollDistance, setScrollDistance] = useState(0);
Expand Down
6 changes: 6 additions & 0 deletions packages/tdesign-react/.changelog/pr-4178.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
pr_number: 4178
contributor: RylanBot
---

- fix(TagInput): 修复 `excessTagsDisplayType="break-line"` 时,`suffix` 没有固定在右侧的问题 @RylanBot ([#4178](https://github.com/Tencent/tdesign-react/pull/4178))
Loading