feat: manually mirror opencoze's code from bytedance
Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
.container {
|
||||
.icon {
|
||||
color: #4d53e8;
|
||||
|
||||
&>svg {
|
||||
color: #4d53e8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.disabled {
|
||||
.icon {
|
||||
color: var(--light-usage-disabled-color-disabled-text, rgb(28 31 35 / 35%));
|
||||
|
||||
&>svg {
|
||||
color: var(--light-usage-disabled-color-disabled-text, rgb(28 31 35 / 35%));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { IconCozAddNode } from '@coze-arch/coze-design/icons';
|
||||
import { IconButton, type ButtonProps } from '@coze-arch/coze-design';
|
||||
import { IconAdd } from '@coze-arch/bot-icons';
|
||||
|
||||
import styles from './index.module.less';
|
||||
|
||||
type AddOperationProps = React.PropsWithChildren<{
|
||||
readonly?: boolean;
|
||||
onClick: React.MouseEventHandler<HTMLButtonElement>;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
disabled?: boolean;
|
||||
subitem?: boolean;
|
||||
size?: ButtonProps['size'];
|
||||
color?: ButtonProps['color'];
|
||||
}>;
|
||||
|
||||
export default function AddOperation({
|
||||
readonly,
|
||||
onClick,
|
||||
className,
|
||||
style,
|
||||
disabled,
|
||||
subitem = false,
|
||||
size,
|
||||
color,
|
||||
...restProps
|
||||
}: AddOperationProps) {
|
||||
if (readonly) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<IconButton
|
||||
data-testid={restProps['data-testid']}
|
||||
onClick={onClick}
|
||||
className={classNames(
|
||||
styles.container,
|
||||
disabled ? styles.disabled : null,
|
||||
className,
|
||||
)}
|
||||
style={style}
|
||||
icon={subitem ? <IconCozAddNode /> : <IconAdd className={styles.icon} />}
|
||||
disabled={disabled}
|
||||
size={size}
|
||||
color={color}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/* stylelint-disable declaration-no-important */
|
||||
.popup_container {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.nano {
|
||||
pointer-events: none;
|
||||
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
|
||||
align-self: stretch;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
:global {
|
||||
.semi-portal-inner {
|
||||
left: 50% !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
&.top-level {
|
||||
max-width: 400px;
|
||||
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
line-height: 22px;
|
||||
word-break: break-word;
|
||||
|
||||
border-radius: 6px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { type PropsWithChildren, useRef } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { Tooltip, type TooltipProps } from '@coze-arch/coze-design';
|
||||
|
||||
import styles from './index.module.less';
|
||||
|
||||
type AutoSizeTooltipProps = PropsWithChildren<
|
||||
{
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
containerClassName?: string;
|
||||
containerStyle?: React.CSSProperties;
|
||||
tooltipClassName?: string;
|
||||
tooltipStyle?: React.CSSProperties;
|
||||
} & Omit<TooltipProps, 'className' | 'style'>
|
||||
>;
|
||||
|
||||
export default function AutoSizeTooltip({
|
||||
children,
|
||||
className,
|
||||
style,
|
||||
tooltipClassName,
|
||||
tooltipStyle,
|
||||
containerClassName,
|
||||
containerStyle,
|
||||
...rest
|
||||
}: AutoSizeTooltipProps) {
|
||||
const nanoRef = useRef<HTMLDivElement | null>(null);
|
||||
const renderContent = () => (
|
||||
<>
|
||||
<div
|
||||
ref={nanoRef}
|
||||
className={classNames(styles.nano, containerClassName)}
|
||||
style={containerStyle}
|
||||
/>
|
||||
<Tooltip
|
||||
{...rest}
|
||||
className={classNames(
|
||||
styles.tooltip,
|
||||
styles['top-level'],
|
||||
tooltipClassName,
|
||||
)}
|
||||
style={{ left: 0, ...tooltipStyle }}
|
||||
>
|
||||
{children}
|
||||
</Tooltip>
|
||||
</>
|
||||
);
|
||||
return (
|
||||
<div
|
||||
className={classNames(styles.popup_container, className)}
|
||||
style={style}
|
||||
>
|
||||
{renderContent()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
.uiBanner {
|
||||
margin: 8px 16px;
|
||||
padding: 12px 24px;
|
||||
|
||||
:global {
|
||||
.semi-banner-extra {
|
||||
position: absolute;
|
||||
top: 22px;
|
||||
right: 56px;
|
||||
margin-top: 0;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.semi-banner-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.semi-banner-icon {
|
||||
margin-right: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 对 semi-ui 的 banner 做一个简单的样式封装,符合 UX 设计稿规范
|
||||
*/
|
||||
|
||||
import { type FC } from 'react';
|
||||
|
||||
import classnames from 'classnames';
|
||||
import { Banner, type BannerProps } from '@coze-arch/coze-design';
|
||||
import { IconClose } from '@douyinfe/semi-icons';
|
||||
|
||||
import styles from './index.module.less';
|
||||
|
||||
export const UIBanner: FC<BannerProps> = props => (
|
||||
<Banner
|
||||
bordered
|
||||
closeIcon={<IconClose />}
|
||||
fullMode={false}
|
||||
{...props}
|
||||
className={classnames(styles.uiBanner, props.className)}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,36 @@
|
||||
.input-wrapper {
|
||||
width: 100%;
|
||||
span {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.error-content {
|
||||
height: 20px;
|
||||
}
|
||||
.error-float {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
}
|
||||
.error-text {
|
||||
font-size: 12px;
|
||||
padding-top: 2px;
|
||||
padding-left: 12px;
|
||||
color: @error-red;
|
||||
position: absolute;
|
||||
}
|
||||
.input {
|
||||
input {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
.limit-count {
|
||||
padding-left: 8px;
|
||||
padding-right: 12px;
|
||||
overflow: hidden;
|
||||
color: var(--light-usage-text-color-text-3, rgba(28, 31, 35, 0.35));
|
||||
font-size: 12px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 16px;
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, {
|
||||
type ComponentProps,
|
||||
useRef,
|
||||
useImperativeHandle,
|
||||
useMemo,
|
||||
useEffect,
|
||||
type ForwardedRef,
|
||||
} from 'react';
|
||||
|
||||
import isNumber from 'lodash-es/isNumber';
|
||||
import cs from 'classnames';
|
||||
import { useReactive } from 'ahooks';
|
||||
import {
|
||||
Input as UIInput,
|
||||
type InputProps,
|
||||
type TooltipProps,
|
||||
} from '@coze-arch/coze-design';
|
||||
|
||||
import AutoSizeTooltip from '../auto-size-tooltip';
|
||||
|
||||
import s from './index.module.less';
|
||||
|
||||
export interface WorkflowSLInputRefType {
|
||||
triggerFocus?: () => void;
|
||||
}
|
||||
|
||||
export type WorkflowSLInputProps = ComponentProps<typeof UIInput> & {
|
||||
value: string | undefined;
|
||||
onRef?: ForwardedRef<WorkflowSLInputRefType>;
|
||||
ellipsis?: boolean;
|
||||
handleChange?: (v: string) => void;
|
||||
handleBlur?: (v: string) => void;
|
||||
handleFocus?: (v: string) => void;
|
||||
ellipsisTooltipProps?: TooltipProps;
|
||||
onFocusTooltipProps?: TooltipProps;
|
||||
tooltipProps?: TooltipProps;
|
||||
inputProps?: InputProps;
|
||||
errorMsg?: string;
|
||||
errorMsgFloat?: boolean;
|
||||
maxCount?: number;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
};
|
||||
|
||||
const SL_INPUT_TIMEOUT = 10;
|
||||
|
||||
export default function WorkflowSLInput(props: WorkflowSLInputProps) {
|
||||
const { ellipsis = true, maxCount } = props;
|
||||
const showCount = isNumber(maxCount) && maxCount > 0;
|
||||
useImperativeHandle(props.onRef, () => ({
|
||||
triggerFocus,
|
||||
}));
|
||||
const $state = useReactive({
|
||||
value: props.value,
|
||||
inputOnFocus: false,
|
||||
inputEle: false,
|
||||
});
|
||||
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const triggerFocus = () => {
|
||||
$state.inputEle = true;
|
||||
inputRef?.current?.focus();
|
||||
};
|
||||
|
||||
const onFocus = () => {
|
||||
$state.inputOnFocus = true;
|
||||
$state.inputEle = true;
|
||||
props?.handleFocus?.($state.value || '');
|
||||
};
|
||||
|
||||
const onBlur = (e: React.FocusEvent<HTMLInputElement>) => {
|
||||
$state.inputOnFocus = false;
|
||||
props?.handleBlur?.($state.value || '');
|
||||
props?.onBlur?.(e);
|
||||
$state.inputEle = false;
|
||||
};
|
||||
|
||||
const onChange = (v: string) => {
|
||||
$state.value = v;
|
||||
props?.handleChange?.(v);
|
||||
};
|
||||
|
||||
const onclick = () => {
|
||||
if (!$state.inputEle) {
|
||||
setTimeout(() => {
|
||||
inputRef?.current?.focus();
|
||||
}, SL_INPUT_TIMEOUT);
|
||||
}
|
||||
$state.inputEle = true;
|
||||
};
|
||||
const hasEllipsis = useMemo(() => {
|
||||
const clientWidth = inputRef.current?.clientWidth || 0;
|
||||
const scrollWidth = inputRef.current?.scrollWidth || 0;
|
||||
return clientWidth < scrollWidth - 1;
|
||||
}, [
|
||||
ellipsis,
|
||||
$state.inputOnFocus,
|
||||
$state.value,
|
||||
inputRef.current?.clientWidth,
|
||||
inputRef.current?.scrollWidth,
|
||||
$state.inputEle,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
$state.value = props.value;
|
||||
}, [props.value]);
|
||||
|
||||
const LimitCountNode = (
|
||||
<span className={s['limit-count']}>
|
||||
{$state.value?.length || 0}/{maxCount}
|
||||
</span>
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cs(s['input-wrapper'], props.className)}
|
||||
style={props.style}
|
||||
>
|
||||
{!$state.inputEle && hasEllipsis ? (
|
||||
<AutoSizeTooltip
|
||||
content={$state.value}
|
||||
position={'top'}
|
||||
showArrow
|
||||
mouseEnterDelay={300}
|
||||
{...props.tooltipProps}
|
||||
>
|
||||
<div
|
||||
className={cs(props?.errorMsg ? s['error-wrapper'] : null)}
|
||||
onClick={onclick}
|
||||
>
|
||||
<UIInput
|
||||
{...props.inputProps}
|
||||
validateStatus={props.validateStatus}
|
||||
ref={inputRef}
|
||||
value={$state.value}
|
||||
className={ellipsis ? s.input : ''}
|
||||
suffix={showCount ? LimitCountNode : undefined}
|
||||
></UIInput>
|
||||
</div>
|
||||
</AutoSizeTooltip>
|
||||
) : (
|
||||
<div className={cs(props?.errorMsg ? s['error-wrapper'] : null)}>
|
||||
<AutoSizeTooltip
|
||||
{...props.onFocusTooltipProps}
|
||||
trigger="custom"
|
||||
visible={
|
||||
Boolean(props.onFocusTooltipProps?.content) && $state.inputOnFocus
|
||||
}
|
||||
showArrow
|
||||
>
|
||||
<UIInput
|
||||
{...props.inputProps}
|
||||
validateStatus={props.validateStatus}
|
||||
ref={inputRef}
|
||||
value={$state.value}
|
||||
className={ellipsis ? s.input : ''}
|
||||
onChange={onChange}
|
||||
onFocus={onFocus}
|
||||
onBlur={onBlur}
|
||||
suffix={showCount ? LimitCountNode : undefined}
|
||||
></UIInput>
|
||||
</AutoSizeTooltip>
|
||||
</div>
|
||||
)}
|
||||
{props?.errorMsg ? (
|
||||
<div
|
||||
className={cs(
|
||||
s['error-content'],
|
||||
props?.errorMsgFloat ? s['error-float'] : null,
|
||||
)}
|
||||
>
|
||||
<div className={s['error-text']}>{props?.errorMsg}</div>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/* stylelint-disable declaration-no-important */
|
||||
.input-wrapper {
|
||||
width: 100%;
|
||||
|
||||
span {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.error-wrapper {
|
||||
:global {
|
||||
.semi-input-wrapper {
|
||||
border: 1px solid @error-red;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.error-content {
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.error-float {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.error-text {
|
||||
position: absolute;
|
||||
|
||||
padding-top: 2px;
|
||||
padding-left: 12px;
|
||||
|
||||
font-size: 12px;
|
||||
color: @error-red;
|
||||
}
|
||||
|
||||
.textarea-pd {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.inputting {
|
||||
textarea {
|
||||
.textarea-pd;
|
||||
}
|
||||
}
|
||||
|
||||
.input-blur {
|
||||
textarea {
|
||||
.textarea-pd;
|
||||
|
||||
overflow: hidden;
|
||||
display: -webkit-box;
|
||||
|
||||
text-overflow: ellipsis;
|
||||
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
}
|
||||
}
|
||||
|
||||
.text-input-placeholder {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
|
||||
textarea {
|
||||
padding-top: 4px !important;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React, {
|
||||
type ComponentProps,
|
||||
useState,
|
||||
useRef,
|
||||
type ForwardedRef,
|
||||
} from 'react';
|
||||
|
||||
import cs from 'classnames';
|
||||
import { TextArea } from '@coze-arch/coze-design';
|
||||
import { sleep } from '@coze-arch/bot-utils';
|
||||
import { type TooltipProps } from '@coze-arch/bot-semi/Tooltip';
|
||||
import { type TextAreaProps } from '@coze-arch/bot-semi/Input';
|
||||
|
||||
import AutoSizeTooltip from '../auto-size-tooltip';
|
||||
|
||||
import s from './index.module.less';
|
||||
|
||||
export interface WorkflowSLTextAreaRefType {
|
||||
triggerFocus?: () => void;
|
||||
}
|
||||
|
||||
export type WorkflowSLTextAreaProps = ComponentProps<typeof TextArea> & {
|
||||
value: string | undefined;
|
||||
onRef?: ForwardedRef<WorkflowSLTextAreaRefType>;
|
||||
handleChange?: (v: string) => void;
|
||||
handleBlur?: () => void;
|
||||
handleFocus?: () => void;
|
||||
ellipsisTooltipProps?: TooltipProps;
|
||||
onFocusTooltipProps?: TooltipProps;
|
||||
inputFocusProps: TextAreaProps;
|
||||
inputBlurProps?: TextAreaProps;
|
||||
textAreaProps?: TextAreaProps;
|
||||
errorMsg?: string;
|
||||
errorMsgFloat?: boolean;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* @component TextArea 在 Workflow 场景下的二次封装;
|
||||
* focus(inputting) 的时候提供多行滚动输入能力,blur 的时候提供 ellipsis 和 tooltip 提示能力
|
||||
*/
|
||||
export default function WorkflowSLTextArea(props: WorkflowSLTextAreaProps) {
|
||||
const { value, handleChange, inputFocusProps, inputBlurProps, disabled } =
|
||||
props;
|
||||
|
||||
const [focus, setFocus] = useState<boolean>(false);
|
||||
|
||||
const selectionCacheRef = useRef<number>();
|
||||
const focusInputRef = useRef<HTMLTextAreaElement>(null);
|
||||
const blurInputRef = useRef<HTMLTextAreaElement>(null);
|
||||
|
||||
const hasEllipsis = (() => {
|
||||
const clientHeight =
|
||||
blurInputRef.current?.clientHeight ||
|
||||
focusInputRef.current?.clientHeight ||
|
||||
0;
|
||||
const scrollHeight =
|
||||
blurInputRef.current?.scrollHeight ||
|
||||
focusInputRef.current?.scrollHeight ||
|
||||
0;
|
||||
|
||||
return clientHeight < scrollHeight - 1 && (value as string).length > 0;
|
||||
})();
|
||||
|
||||
/* 非focus状态下仅用于展示,溢出时提供tooltip */
|
||||
const InputDisplay = () => {
|
||||
const handleFocus = async () => {
|
||||
// 1. 获取光标位置,focus后定位到相同位置
|
||||
await sleep(50);
|
||||
selectionCacheRef.current = blurInputRef.current?.selectionStart;
|
||||
setFocus(true);
|
||||
|
||||
// 2. 触发真正输入组件的focus
|
||||
await sleep(50);
|
||||
focusInputRef.current?.focus();
|
||||
};
|
||||
|
||||
if (!hasEllipsis) {
|
||||
return (
|
||||
<TextArea
|
||||
className={s['text-input-placeholder']}
|
||||
{...inputBlurProps}
|
||||
ref={blurInputRef}
|
||||
value={value}
|
||||
onFocus={handleFocus}
|
||||
disabled={disabled}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<AutoSizeTooltip
|
||||
content={
|
||||
<article
|
||||
style={{
|
||||
wordWrap: 'break-word',
|
||||
wordBreak: 'normal',
|
||||
textAlign: 'left',
|
||||
}}
|
||||
>
|
||||
{value}
|
||||
</article>
|
||||
}
|
||||
position={'top'}
|
||||
showArrow
|
||||
mouseEnterDelay={300}
|
||||
trigger="hover"
|
||||
>
|
||||
<TextArea
|
||||
className={s['.text-input-placeholder']}
|
||||
{...inputBlurProps}
|
||||
ref={blurInputRef}
|
||||
value={value}
|
||||
onFocus={handleFocus}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</AutoSizeTooltip>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={cs(s['input-wrapper'], props.className)}>
|
||||
<div className={cs(props?.errorMsg ? s['error-wrapper'] : null)}>
|
||||
{!focus ? (
|
||||
<InputDisplay />
|
||||
) : (
|
||||
<TextArea
|
||||
{...inputFocusProps}
|
||||
ref={focusInputRef}
|
||||
value={value}
|
||||
onChange={handleChange}
|
||||
onFocus={() => {
|
||||
if (selectionCacheRef.current !== undefined) {
|
||||
focusInputRef.current?.setSelectionRange(
|
||||
selectionCacheRef.current,
|
||||
selectionCacheRef.current,
|
||||
);
|
||||
|
||||
selectionCacheRef.current = undefined;
|
||||
}
|
||||
props.handleFocus?.();
|
||||
}}
|
||||
onBlur={() => {
|
||||
setFocus(false);
|
||||
props.handleBlur?.();
|
||||
}}
|
||||
disabled={disabled}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{props?.errorMsg ? (
|
||||
<div
|
||||
className={cs(
|
||||
s['error-content'],
|
||||
props?.errorMsgFloat ? s['error-float'] : null,
|
||||
)}
|
||||
>
|
||||
<div className={s['error-text']}>{props?.errorMsg}</div>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user