chore: common components
This commit is contained in:
@@ -1,4 +1,6 @@
|
|||||||
:local(.wrapper) {
|
:local(.wrapper) {
|
||||||
|
@wrapheight: 54px;
|
||||||
|
@inputheight: 32px;
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -10,6 +12,31 @@
|
|||||||
border-radius: 28px;
|
border-radius: 28px;
|
||||||
padding-inline: 12px;
|
padding-inline: 12px;
|
||||||
padding-block: 20px 0;
|
padding-block: 20px 0;
|
||||||
|
|
||||||
|
&.seal-input-wrapper-disabled {
|
||||||
|
background-color: var(--ant-color-bg-container-disabled);
|
||||||
|
cursor: not-allowed;
|
||||||
|
&:hover {
|
||||||
|
border-color: var(--ant-color-border);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.seal-textarea-wrapper {
|
||||||
|
height: auto;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
padding-right: 10px;
|
||||||
|
}
|
||||||
|
&.validate-status-error {
|
||||||
|
border-width: var(--ant-line-width);
|
||||||
|
border-style: var(--ant-line-type);
|
||||||
|
border-color: var(--ant-color-error);
|
||||||
|
&:hover {
|
||||||
|
border-color: var(--ant-color-error-border-hover);
|
||||||
|
}
|
||||||
|
&:focus-within {
|
||||||
|
border-color: var(--ant-color-error);
|
||||||
|
}
|
||||||
|
}
|
||||||
&:hover {
|
&:hover {
|
||||||
border-color: var(--ant-input-hover-border-color);
|
border-color: var(--ant-input-hover-border-color);
|
||||||
transition: all 0.2s ease;
|
transition: all 0.2s ease;
|
||||||
@@ -37,13 +64,92 @@
|
|||||||
transition: all 0.2s var(--seal-transition-func);
|
transition: all 0.2s var(--seal-transition-func);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
:global(.ant-input) {
|
// ==================== select ==================
|
||||||
|
:global(.ant-select) {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
border: none;
|
||||||
|
box-shadow: none;
|
||||||
|
height: @inputheight;
|
||||||
|
}
|
||||||
|
:global(.ant-select-selector) {
|
||||||
|
border: none !important;
|
||||||
|
padding-block: 5px;
|
||||||
|
padding-inline: 12px;
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
:global(.ant-select-selection-item) {
|
||||||
|
height: @inputheight;
|
||||||
|
}
|
||||||
|
:global(
|
||||||
|
.ant-select-outlined.ant-select-disabled:not(.ant-select-customize-input)
|
||||||
|
.ant-select-selector
|
||||||
|
) {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
// ==================== input ====================
|
||||||
|
:global(.ant-input),
|
||||||
|
:global(.ant-input-password) {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border: none;
|
border: none;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
padding-block: 5px;
|
padding-block: 5px;
|
||||||
padding-inline: 12px;
|
padding-inline: 12px;
|
||||||
height: 32px;
|
height: @inputheight;
|
||||||
|
}
|
||||||
|
:global(.ant-input-number) {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
border: none;
|
||||||
|
box-shadow: none;
|
||||||
|
padding: 0;
|
||||||
|
height: @inputheight;
|
||||||
|
}
|
||||||
|
:global(.ant-input-outlined) {
|
||||||
|
&.seal-textarea {
|
||||||
|
min-height: 100px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
:global(.ant-input.ant-input-disabled) {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
:global(input.ant-input-number-input) {
|
||||||
|
height: @inputheight;
|
||||||
|
padding-block: 5px;
|
||||||
|
padding-inline: 12px;
|
||||||
|
}
|
||||||
|
:global(.ant-input-group) {
|
||||||
|
position: static;
|
||||||
|
}
|
||||||
|
:global(.ant-input-group-addon) {
|
||||||
|
inset-inline-start: unset !important;
|
||||||
|
border-radius: 0 28px 28px 0;
|
||||||
|
width: 30px;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
:global(.ant-input-group-addon:hover) {
|
||||||
|
background-color: transparent !important;
|
||||||
|
}
|
||||||
|
:global(.ant-input-group-wrapper-disabled .ant-input-group-addon) {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
:global(.ant-input-group-wrapper-disabled .ant-input-group-addon:hover) {
|
||||||
|
background-color: transparent !important;
|
||||||
|
}
|
||||||
|
:global(.ant-input-search-button) {
|
||||||
|
position: absolute;
|
||||||
|
top: -20px;
|
||||||
|
right: -11px;
|
||||||
|
border-radius: 0 28px 28px 0 !important;
|
||||||
|
overflow: hidden;
|
||||||
|
border: none;
|
||||||
|
height: 52px;
|
||||||
|
border-left: var(--ant-line-width) var(--ant-line-type)
|
||||||
|
var(--ant-color-border);
|
||||||
|
}
|
||||||
|
:global(.ant-input-number-handler-wrap) {
|
||||||
|
top: -20px;
|
||||||
|
height: @wrapheight - 2px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ interface WrapperProps {
|
|||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
label: string;
|
label: string;
|
||||||
isFocus: boolean;
|
isFocus: boolean;
|
||||||
|
status?: string;
|
||||||
|
className?: string;
|
||||||
|
disabled?: boolean;
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -11,10 +14,21 @@ const Wrapper: React.FC<WrapperProps> = ({
|
|||||||
children,
|
children,
|
||||||
label,
|
label,
|
||||||
isFocus,
|
isFocus,
|
||||||
|
status,
|
||||||
|
className,
|
||||||
|
disabled,
|
||||||
onClick
|
onClick
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div className={wrapperStyle.wrapper} onClick={onClick}>
|
<div
|
||||||
|
className={classNames(
|
||||||
|
wrapperStyle.wrapper,
|
||||||
|
wrapperStyle[`validate-status-${status}`],
|
||||||
|
disabled ? wrapperStyle['seal-input-wrapper-disabled'] : '',
|
||||||
|
className ? wrapperStyle[className] : ''
|
||||||
|
)}
|
||||||
|
onClick={onClick}
|
||||||
|
>
|
||||||
<label
|
<label
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
import type { InputNumberProps } from 'antd';
|
||||||
|
import { Form, InputNumber } from 'antd';
|
||||||
|
import { useEffect, useRef, useState } from 'react';
|
||||||
|
import Wrapper from './components/wrapper';
|
||||||
|
import { SealFormItemProps } from './types';
|
||||||
|
|
||||||
|
const SealInputNumber: React.FC<InputNumberProps & SealFormItemProps> = (
|
||||||
|
props
|
||||||
|
) => {
|
||||||
|
const { label, placeholder, ...rest } = props;
|
||||||
|
const [isFocus, setIsFocus] = useState(false);
|
||||||
|
const inputRef = useRef<any>(null);
|
||||||
|
const { status } = Form.Item.useStatus();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (props.value) {
|
||||||
|
setIsFocus(true);
|
||||||
|
}
|
||||||
|
}, [props.value]);
|
||||||
|
|
||||||
|
const handleClickWrapper = () => {
|
||||||
|
if (!props.disabled && !isFocus) {
|
||||||
|
inputRef.current?.focus?.();
|
||||||
|
setIsFocus(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleChange = (e: any) => {
|
||||||
|
props.onChange?.(e);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOnFocus = (e: any) => {
|
||||||
|
setIsFocus(true);
|
||||||
|
props.onFocus?.(e);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOnBlur = (e: any) => {
|
||||||
|
if (!inputRef.current?.value) {
|
||||||
|
setIsFocus(false);
|
||||||
|
props.onBlur?.(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInput = (e: any) => {
|
||||||
|
props.onInput?.(e);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Wrapper
|
||||||
|
status={status}
|
||||||
|
label={label || (placeholder as string)}
|
||||||
|
isFocus={isFocus}
|
||||||
|
disabled={props.disabled}
|
||||||
|
onClick={handleClickWrapper}
|
||||||
|
>
|
||||||
|
<InputNumber
|
||||||
|
{...rest}
|
||||||
|
ref={inputRef}
|
||||||
|
onFocus={handleOnFocus}
|
||||||
|
onBlur={handleOnBlur}
|
||||||
|
onInput={handleInput}
|
||||||
|
onChange={(e) => handleChange(e)}
|
||||||
|
></InputNumber>
|
||||||
|
</Wrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SealInputNumber;
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
import { Form, Input } from 'antd';
|
||||||
|
import type { SearchProps } from 'antd/es/input/Search';
|
||||||
|
import { useEffect, useRef, useState } from 'react';
|
||||||
|
import Wrapper from './components/wrapper';
|
||||||
|
import { SealFormItemProps } from './types';
|
||||||
|
|
||||||
|
type OnSearch = (
|
||||||
|
value: string,
|
||||||
|
event?:
|
||||||
|
| React.ChangeEvent<HTMLInputElement>
|
||||||
|
| React.MouseEvent<HTMLElement>
|
||||||
|
| React.KeyboardEvent<HTMLInputElement>,
|
||||||
|
info?: {
|
||||||
|
source?: 'clear' | 'input';
|
||||||
|
}
|
||||||
|
) => void;
|
||||||
|
|
||||||
|
const SealInputSearch: React.FC<SearchProps & SealFormItemProps> = (props) => {
|
||||||
|
const { label, placeholder, ...rest } = props;
|
||||||
|
const [isFocus, setIsFocus] = useState(false);
|
||||||
|
const inputRef = useRef<any>(null);
|
||||||
|
const { status } = Form.Item.useStatus();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (props.value) {
|
||||||
|
setIsFocus(true);
|
||||||
|
}
|
||||||
|
}, [props.value]);
|
||||||
|
|
||||||
|
const handleClickWrapper = () => {
|
||||||
|
if (!props.disabled && !isFocus) {
|
||||||
|
inputRef.current?.focus?.();
|
||||||
|
setIsFocus(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleChange = (e: any) => {
|
||||||
|
props.onChange?.(e);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOnFocus = (e: any) => {
|
||||||
|
setIsFocus(true);
|
||||||
|
props.onFocus?.(e);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOnBlur = (e: any) => {
|
||||||
|
if (!inputRef.current?.input?.value) {
|
||||||
|
setIsFocus(false);
|
||||||
|
props.onBlur?.(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSearch: OnSearch = (...args) => {
|
||||||
|
props.onSearch?.(...args);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Wrapper
|
||||||
|
status={status}
|
||||||
|
label={label || (placeholder as string)}
|
||||||
|
isFocus={isFocus}
|
||||||
|
disabled={props.disabled}
|
||||||
|
onClick={handleClickWrapper}
|
||||||
|
>
|
||||||
|
<Input.Search
|
||||||
|
{...rest}
|
||||||
|
ref={inputRef}
|
||||||
|
onFocus={handleOnFocus}
|
||||||
|
onBlur={handleOnBlur}
|
||||||
|
onSearch={handleSearch}
|
||||||
|
onChange={(e) => handleChange(e)}
|
||||||
|
></Input.Search>
|
||||||
|
</Wrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SealInputSearch;
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import type { InputProps } from 'antd';
|
||||||
|
import { Form, Input } from 'antd';
|
||||||
|
import { useEffect, useRef, useState } from 'react';
|
||||||
|
import Wrapper from './components/wrapper';
|
||||||
|
import { SealFormItemProps } from './types';
|
||||||
|
|
||||||
|
const SealPassword: React.FC<InputProps & SealFormItemProps> = (props) => {
|
||||||
|
const { label, placeholder, ...rest } = props;
|
||||||
|
const [isFocus, setIsFocus] = useState(false);
|
||||||
|
const inputRef = useRef<any>(null);
|
||||||
|
const { status } = Form.Item.useStatus();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (props.value) {
|
||||||
|
setIsFocus(true);
|
||||||
|
}
|
||||||
|
}, [props.value]);
|
||||||
|
|
||||||
|
const handleClickWrapper = () => {
|
||||||
|
if (!props.disabled && !isFocus) {
|
||||||
|
inputRef.current?.focus?.();
|
||||||
|
setIsFocus(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleChange = (e: any) => {
|
||||||
|
props.onChange?.(e);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOnFocus = (e: any) => {
|
||||||
|
setIsFocus(true);
|
||||||
|
props.onFocus?.(e);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOnBlur = (e: any) => {
|
||||||
|
if (!inputRef.current?.input?.value) {
|
||||||
|
setIsFocus(false);
|
||||||
|
props.onBlur?.(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Wrapper
|
||||||
|
status={status}
|
||||||
|
label={label || (placeholder as string)}
|
||||||
|
isFocus={isFocus}
|
||||||
|
disabled={props.disabled}
|
||||||
|
onClick={handleClickWrapper}
|
||||||
|
>
|
||||||
|
<Input.Password
|
||||||
|
{...rest}
|
||||||
|
ref={inputRef}
|
||||||
|
onFocus={handleOnFocus}
|
||||||
|
onBlur={handleOnBlur}
|
||||||
|
onChange={(e) => handleChange(e)}
|
||||||
|
></Input.Password>
|
||||||
|
</Wrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SealPassword;
|
||||||
@@ -1,27 +1,18 @@
|
|||||||
import type { InputProps } from 'antd';
|
import type { InputProps } from 'antd';
|
||||||
import { Input } from 'antd';
|
import { Form, Input } from 'antd';
|
||||||
|
import type { TextAreaProps } from 'antd/es/input/TextArea';
|
||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import Wrapper from './components/wrapper';
|
import Wrapper from './components/wrapper';
|
||||||
|
import SealInputNumber from './input-number';
|
||||||
|
import SealInputSearch from './input-search';
|
||||||
|
import SealPassword from './password';
|
||||||
import { SealFormItemProps } from './types';
|
import { SealFormItemProps } from './types';
|
||||||
|
|
||||||
const TextArea: React.FC<InputProps & SealFormItemProps> = (props) => {
|
const SealTextArea: React.FC<TextAreaProps & SealFormItemProps> = (props) => {
|
||||||
console.log('textarea=========', 121);
|
const { label, placeholder, style, ...rest } = props;
|
||||||
return (
|
|
||||||
<Wrapper label="input">
|
|
||||||
<Input.TextArea
|
|
||||||
placeholder="send your message"
|
|
||||||
autoSize={{ minRows: 1, maxRows: 6 }}
|
|
||||||
size="large"
|
|
||||||
variant="borderless"
|
|
||||||
></Input.TextArea>
|
|
||||||
</Wrapper>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const SealInput: React.FC<InputProps & SealFormItemProps> = (props) => {
|
|
||||||
const { label, placeholder, ...rest } = props;
|
|
||||||
const [isFocus, setIsFocus] = useState(false);
|
const [isFocus, setIsFocus] = useState(false);
|
||||||
const inputRef = useRef<any>(null);
|
const inputRef = useRef<any>(null);
|
||||||
|
const { status } = Form.Item.useStatus();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (props.value) {
|
if (props.value) {
|
||||||
@@ -52,15 +43,84 @@ const SealInput: React.FC<InputProps & SealFormItemProps> = (props) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleInput = (e: any) => {
|
||||||
|
props.onInput?.(e);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Wrapper
|
<Wrapper
|
||||||
|
status={status}
|
||||||
label={label || (placeholder as string)}
|
label={label || (placeholder as string)}
|
||||||
isFocus={isFocus}
|
isFocus={isFocus}
|
||||||
|
className="seal-textarea-wrapper"
|
||||||
|
disabled={props.disabled}
|
||||||
|
onClick={handleClickWrapper}
|
||||||
|
>
|
||||||
|
<Input.TextArea
|
||||||
|
{...rest}
|
||||||
|
ref={inputRef}
|
||||||
|
style={{ minHeight: '80px', ...style }}
|
||||||
|
className="seal-textarea"
|
||||||
|
onFocus={handleOnFocus}
|
||||||
|
onBlur={handleOnBlur}
|
||||||
|
onInput={handleInput}
|
||||||
|
onChange={(e) => handleChange(e)}
|
||||||
|
></Input.TextArea>
|
||||||
|
</Wrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const SealInput: React.FC<InputProps & SealFormItemProps> = (props) => {
|
||||||
|
const { label, placeholder, ...rest } = props;
|
||||||
|
const [isFocus, setIsFocus] = useState(false);
|
||||||
|
const inputRef = useRef<any>(null);
|
||||||
|
const { status } = Form.Item.useStatus();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (props.value) {
|
||||||
|
setIsFocus(true);
|
||||||
|
}
|
||||||
|
}, [props.value]);
|
||||||
|
|
||||||
|
const handleClickWrapper = () => {
|
||||||
|
if (!props.disabled && !isFocus) {
|
||||||
|
inputRef.current?.focus?.();
|
||||||
|
setIsFocus(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleChange = (e: any) => {
|
||||||
|
props.onChange?.(e);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOnFocus = (e: any) => {
|
||||||
|
setIsFocus(true);
|
||||||
|
props.onFocus?.(e);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOnBlur = (e: any) => {
|
||||||
|
if (!inputRef.current?.input?.value) {
|
||||||
|
setIsFocus(false);
|
||||||
|
props.onBlur?.(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInput = (e: any) => {
|
||||||
|
props.onInput?.(e);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Wrapper
|
||||||
|
status={status}
|
||||||
|
label={label || (placeholder as string)}
|
||||||
|
isFocus={isFocus}
|
||||||
|
disabled={props.disabled}
|
||||||
onClick={handleClickWrapper}
|
onClick={handleClickWrapper}
|
||||||
>
|
>
|
||||||
<Input
|
<Input
|
||||||
{...rest}
|
{...rest}
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
|
onInput={handleInput}
|
||||||
onFocus={handleOnFocus}
|
onFocus={handleOnFocus}
|
||||||
onBlur={handleOnBlur}
|
onBlur={handleOnBlur}
|
||||||
onChange={(e) => handleChange(e)}
|
onChange={(e) => handleChange(e)}
|
||||||
@@ -69,4 +129,10 @@ const SealInput: React.FC<InputProps & SealFormItemProps> = (props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default { TextArea, Input: SealInput };
|
export default {
|
||||||
|
TextArea: SealTextArea,
|
||||||
|
Input: SealInput,
|
||||||
|
Password: SealPassword,
|
||||||
|
Number: SealInputNumber,
|
||||||
|
Search: SealInputSearch
|
||||||
|
} as Record<string, React.FC<InputProps & SealFormItemProps>>;
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import { isNotEmptyValue } from '@/utils/index';
|
||||||
|
import type { SelectProps } from 'antd';
|
||||||
|
import { Form, Select } from 'antd';
|
||||||
|
import { useEffect, useRef, useState } from 'react';
|
||||||
|
import Wrapper from './components/wrapper';
|
||||||
|
import { SealFormItemProps } from './types';
|
||||||
|
|
||||||
|
const SealSelect: React.FC<SelectProps & SealFormItemProps> = (props) => {
|
||||||
|
const { label, placeholder, children, ...rest } = props;
|
||||||
|
const [isFocus, setIsFocus] = useState(false);
|
||||||
|
const inputRef = useRef<any>(null);
|
||||||
|
const { status } = Form.Item.useStatus();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isNotEmptyValue(props.value)) {
|
||||||
|
setIsFocus(true);
|
||||||
|
}
|
||||||
|
}, [props.value]);
|
||||||
|
|
||||||
|
const handleClickWrapper = () => {
|
||||||
|
if (!props.disabled && !isFocus) {
|
||||||
|
inputRef.current?.focus?.();
|
||||||
|
setIsFocus(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleChange = (val: any, options: any) => {
|
||||||
|
if (isNotEmptyValue(val)) {
|
||||||
|
setIsFocus(true);
|
||||||
|
} else {
|
||||||
|
setIsFocus(false);
|
||||||
|
}
|
||||||
|
props.onChange?.(val, options);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOnFocus = (e: any) => {
|
||||||
|
setIsFocus(true);
|
||||||
|
props.onFocus?.(e);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOnBlur = (e: any) => {
|
||||||
|
props.onBlur?.(e);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOnSearch = (val: any) => {
|
||||||
|
props.onSearch?.(val);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Wrapper
|
||||||
|
status={status}
|
||||||
|
label={label || (placeholder as string)}
|
||||||
|
isFocus={isFocus}
|
||||||
|
disabled={props.disabled}
|
||||||
|
onClick={handleClickWrapper}
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
{...rest}
|
||||||
|
ref={inputRef}
|
||||||
|
onFocus={handleOnFocus}
|
||||||
|
onBlur={handleOnBlur}
|
||||||
|
onSearch={handleOnSearch}
|
||||||
|
onChange={(val, options) => handleChange(val, options)}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Select>
|
||||||
|
</Wrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SealSelect;
|
||||||
@@ -27,7 +27,10 @@ html {
|
|||||||
--ant-font-size-sm: var(--font-size-base);
|
--ant-font-size-sm: var(--font-size-base);
|
||||||
--ant-font-size-lg: var(--font-size-base);
|
--ant-font-size-lg: var(--font-size-base);
|
||||||
--ant-font-size-xl: 20px;
|
--ant-font-size-xl: 20px;
|
||||||
|
--ant-font-size: var(--font-size-base);
|
||||||
--ant-padding-sm: 14px;
|
--ant-padding-sm: 14px;
|
||||||
|
--ant-border-radius-lg: 20px;
|
||||||
|
--ant-color-error: #ff4d4f;
|
||||||
|
|
||||||
&.ant-popover {
|
&.ant-popover {
|
||||||
--ant-popover-inner-padding: 26px;
|
--ant-popover-inner-padding: 26px;
|
||||||
@@ -60,10 +63,49 @@ html {
|
|||||||
--ant-select-option-font-size: var(--font-size-base);
|
--ant-select-option-font-size: var(--font-size-base);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
body * {
|
body * {
|
||||||
font-weight: var(--font-weight-normal);
|
font-weight: var(--font-weight-normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
// input
|
||||||
|
.ant-input-outlined.ant-input-status-error:not(.ant-input-disabled) {
|
||||||
|
border: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-input-outlined.ant-input-status-error:not(.ant-input-disabled):focus,
|
||||||
|
.ant-input-outlined.ant-input-status-error:not(
|
||||||
|
.ant-input-disabled
|
||||||
|
):focus-within {
|
||||||
|
border: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
// input number
|
||||||
|
.ant-input-number-outlined.ant-input-number-status-error:not(
|
||||||
|
.ant-input-number-disabled
|
||||||
|
) {
|
||||||
|
border: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-input-number-outlined.ant-input-number-status-error:not(
|
||||||
|
.ant-input-number-disabled
|
||||||
|
):focus,
|
||||||
|
.ant-input-number-outlined.ant-input-number-status-error:not(
|
||||||
|
.ant-input-disabled
|
||||||
|
):focus-within {
|
||||||
|
border: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
// form item help
|
||||||
|
.ant-form-item-with-help .ant-form-item-explain {
|
||||||
|
padding-left: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ======== basic layout style start============
|
// ======== basic layout style start============
|
||||||
.ant-pro-layout {
|
.ant-pro-layout {
|
||||||
height: 100vh;
|
height: 100vh;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import SealInput from '@/components/seal-form/seal-input';
|
import SealInput from '@/components/seal-form/seal-input';
|
||||||
|
import SealSelect from '@/components/seal-form/seal-select';
|
||||||
import { INPUT_WIDTH } from '@/constants';
|
import { INPUT_WIDTH } from '@/constants';
|
||||||
import { Button, Form, Space } from 'antd';
|
import { Button, Form, Select, Space } from 'antd';
|
||||||
|
|
||||||
type ParamsSettingsProps = {
|
type ParamsSettingsProps = {
|
||||||
seed?: number;
|
seed?: number;
|
||||||
@@ -15,7 +16,7 @@ type ParamsSettingsProps = {
|
|||||||
maxTokens?: number;
|
maxTokens?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ParamsSettings: React.FC = () => {
|
const ParamsSettings: React.FC<{ onClose: () => void }> = ({ onClose }) => {
|
||||||
const initialValues = {
|
const initialValues = {
|
||||||
seed: 1,
|
seed: 1,
|
||||||
stopSequence: 1,
|
stopSequence: 1,
|
||||||
@@ -38,6 +39,11 @@ const ParamsSettings: React.FC = () => {
|
|||||||
console.log('handleOnFinishFailed', errorInfo);
|
console.log('handleOnFinishFailed', errorInfo);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
form.resetFields();
|
||||||
|
onClose();
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form
|
<Form
|
||||||
name="modelparams"
|
name="modelparams"
|
||||||
@@ -45,91 +51,134 @@ const ParamsSettings: React.FC = () => {
|
|||||||
onFinish={handleOnFinish}
|
onFinish={handleOnFinish}
|
||||||
onFinishFailed={handleOnFinishFailed}
|
onFinishFailed={handleOnFinishFailed}
|
||||||
>
|
>
|
||||||
<Form.Item<ParamsSettingsProps> name="seed" rules={[{ required: true }]}>
|
<div
|
||||||
<SealInput.Input
|
style={{
|
||||||
label="Seed"
|
maxHeight: '450px',
|
||||||
style={{ width: INPUT_WIDTH.default }}
|
overflow: 'auto',
|
||||||
></SealInput.Input>
|
paddingRight: 'var(--ant-popover-inner-padding)'
|
||||||
</Form.Item>
|
}}
|
||||||
<Form.Item<ParamsSettingsProps>
|
|
||||||
name="stopSequence"
|
|
||||||
rules={[{ required: true }]}
|
|
||||||
>
|
>
|
||||||
<SealInput.Input
|
<Form.Item<ParamsSettingsProps>
|
||||||
label="Stop Sequence"
|
name="seed"
|
||||||
style={{ width: INPUT_WIDTH.default }}
|
rules={[{ required: true }]}
|
||||||
></SealInput.Input>
|
>
|
||||||
</Form.Item>
|
<SealInput.Input
|
||||||
<Form.Item<ParamsSettingsProps>
|
label="Seed"
|
||||||
name="temperature"
|
disabled={true}
|
||||||
rules={[{ required: true }]}
|
style={{ width: INPUT_WIDTH.default }}
|
||||||
>
|
></SealInput.Input>
|
||||||
<SealInput.Input
|
</Form.Item>
|
||||||
label="Temperature"
|
<Form.Item<ParamsSettingsProps>
|
||||||
style={{ width: INPUT_WIDTH.default }}
|
name="select"
|
||||||
></SealInput.Input>
|
rules={[{ required: true }]}
|
||||||
</Form.Item>
|
>
|
||||||
<Form.Item<ParamsSettingsProps> name="topK" rules={[{ required: true }]}>
|
<SealSelect
|
||||||
<SealInput.Input
|
label="Select"
|
||||||
label="TopK"
|
disabled={true}
|
||||||
style={{ width: INPUT_WIDTH.default }}
|
style={{ width: INPUT_WIDTH.default }}
|
||||||
></SealInput.Input>
|
>
|
||||||
</Form.Item>
|
<Select.Option value={1}>1</Select.Option>
|
||||||
<Form.Item<ParamsSettingsProps> name="topP" rules={[{ required: true }]}>
|
<Select.Option value={2}>2</Select.Option>
|
||||||
<SealInput.Input
|
<Select.Option value={3}>3</Select.Option>
|
||||||
label="TopP"
|
</SealSelect>
|
||||||
style={{ width: INPUT_WIDTH.default }}
|
</Form.Item>
|
||||||
></SealInput.Input>
|
<Form.Item<ParamsSettingsProps>
|
||||||
</Form.Item>
|
name="stopSequence"
|
||||||
<Form.Item<ParamsSettingsProps>
|
rules={[{ required: true }]}
|
||||||
name="repeatPenalty"
|
>
|
||||||
rules={[{ required: true }]}
|
<SealInput.Input
|
||||||
>
|
label="Stop Sequence"
|
||||||
<SealInput.Input
|
style={{ width: INPUT_WIDTH.default }}
|
||||||
label="Repeat Penalty"
|
></SealInput.Input>
|
||||||
style={{ width: INPUT_WIDTH.default }}
|
</Form.Item>
|
||||||
></SealInput.Input>
|
<Form.Item<ParamsSettingsProps>
|
||||||
</Form.Item>
|
name="temperature"
|
||||||
<Form.Item<ParamsSettingsProps>
|
rules={[{ required: true }]}
|
||||||
name="repeatLastN"
|
>
|
||||||
rules={[{ required: true }]}
|
<SealInput.Input
|
||||||
>
|
label="Temperature"
|
||||||
<SealInput.Input
|
style={{ width: INPUT_WIDTH.default }}
|
||||||
label="Repeat Last N"
|
disabled={true}
|
||||||
style={{ width: INPUT_WIDTH.default }}
|
></SealInput.Input>
|
||||||
></SealInput.Input>
|
</Form.Item>
|
||||||
</Form.Item>
|
<Form.Item<ParamsSettingsProps>
|
||||||
<Form.Item<ParamsSettingsProps> name="tfsZ" rules={[{ required: true }]}>
|
name="topK"
|
||||||
<SealInput.Input
|
rules={[{ required: true }]}
|
||||||
label="TFSZ"
|
>
|
||||||
style={{ width: INPUT_WIDTH.default }}
|
<SealInput.Input
|
||||||
></SealInput.Input>
|
label="TopK"
|
||||||
</Form.Item>
|
style={{ width: INPUT_WIDTH.default }}
|
||||||
<Form.Item<ParamsSettingsProps>
|
></SealInput.Input>
|
||||||
name="contextLength"
|
</Form.Item>
|
||||||
rules={[{ required: true }]}
|
<Form.Item<ParamsSettingsProps>
|
||||||
>
|
name="topP"
|
||||||
<SealInput.Input
|
rules={[{ required: true }]}
|
||||||
label="Context Length"
|
>
|
||||||
style={{ width: INPUT_WIDTH.default }}
|
<SealInput.Input
|
||||||
></SealInput.Input>
|
label="TopP"
|
||||||
</Form.Item>
|
style={{ width: INPUT_WIDTH.default }}
|
||||||
<Form.Item<ParamsSettingsProps>
|
></SealInput.Input>
|
||||||
name="maxTokens"
|
</Form.Item>
|
||||||
rules={[{ required: true }]}
|
<Form.Item<ParamsSettingsProps>
|
||||||
>
|
name="repeatPenalty"
|
||||||
<SealInput.Input
|
rules={[{ required: true }]}
|
||||||
label="Max Tokens"
|
>
|
||||||
style={{ width: INPUT_WIDTH.default }}
|
<SealInput.Input
|
||||||
></SealInput.Input>
|
label="Repeat Penalty"
|
||||||
</Form.Item>
|
style={{ width: INPUT_WIDTH.default }}
|
||||||
|
></SealInput.Input>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item<ParamsSettingsProps>
|
||||||
|
name="repeatLastN"
|
||||||
|
rules={[{ required: true }]}
|
||||||
|
>
|
||||||
|
<SealInput.Search
|
||||||
|
label="Repeat Last N"
|
||||||
|
style={{ width: INPUT_WIDTH.default }}
|
||||||
|
disabled={true}
|
||||||
|
></SealInput.Search>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item<ParamsSettingsProps>
|
||||||
|
name="tfsZ"
|
||||||
|
rules={[{ required: true }]}
|
||||||
|
>
|
||||||
|
<SealInput.Input
|
||||||
|
label="TFSZ"
|
||||||
|
style={{ width: INPUT_WIDTH.default }}
|
||||||
|
></SealInput.Input>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item<ParamsSettingsProps>
|
||||||
|
name="contextLength"
|
||||||
|
rules={[{ required: true }]}
|
||||||
|
>
|
||||||
|
<SealInput.Number
|
||||||
|
label="Context Length"
|
||||||
|
style={{ width: INPUT_WIDTH.default }}
|
||||||
|
></SealInput.Number>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item<ParamsSettingsProps>
|
||||||
|
name="maxTokens"
|
||||||
|
rules={[{ required: true }]}
|
||||||
|
>
|
||||||
|
<SealInput.TextArea
|
||||||
|
label="Max Tokens"
|
||||||
|
style={{ width: INPUT_WIDTH.default }}
|
||||||
|
></SealInput.TextArea>
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
<Form.Item noStyle>
|
<Form.Item noStyle>
|
||||||
<Space
|
<Space
|
||||||
size={20}
|
size={20}
|
||||||
align="end"
|
align="end"
|
||||||
style={{ width: '100%', display: 'flex', justifyContent: 'end' }}
|
style={{
|
||||||
|
width: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'end',
|
||||||
|
paddingRight: 'var(--ant-popover-inner-padding)',
|
||||||
|
paddingTop: 'var(--ant-popover-inner-padding)'
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Button>Cancel</Button>
|
<Button onClick={handleCancel}>Cancel</Button>
|
||||||
<Button type="primary" htmlType="submit">
|
<Button type="primary" htmlType="submit">
|
||||||
Submit
|
Submit
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import SealPopover from '@/components/popover';
|
|
||||||
import { ControlOutlined } from '@ant-design/icons';
|
import { ControlOutlined } from '@ant-design/icons';
|
||||||
import { PageContainer } from '@ant-design/pro-components';
|
import { PageContainer } from '@ant-design/pro-components';
|
||||||
import { Button, Select, Space } from 'antd';
|
import { Button, Popover, Select, Space } from 'antd';
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import ChatContent from './components/chatContent';
|
import ChatContent from './components/chatContent';
|
||||||
import MessageInput from './components/messageInput';
|
import MessageInput from './components/messageInput';
|
||||||
@@ -17,6 +16,7 @@ const Playground: React.FC = () => {
|
|||||||
const [ModelList, setModelList] = useState(dataList);
|
const [ModelList, setModelList] = useState(dataList);
|
||||||
const [messageList, setMessageList] = useState<any[]>([]);
|
const [messageList, setMessageList] = useState<any[]>([]);
|
||||||
const [selectedModel, setSelectedModel] = useState('llama3:latest');
|
const [selectedModel, setSelectedModel] = useState('llama3:latest');
|
||||||
|
const [showPopover, setShowPopover] = useState(false);
|
||||||
|
|
||||||
const handleSelectChange = (value: string) => {
|
const handleSelectChange = (value: string) => {
|
||||||
setSelectedModel(value);
|
setSelectedModel(value);
|
||||||
@@ -28,6 +28,14 @@ const Playground: React.FC = () => {
|
|||||||
setMessageList(['1']);
|
setMessageList(['1']);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleTogglePopover = () => {
|
||||||
|
setShowPopover(!showPopover);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClosePopover = () => {
|
||||||
|
setShowPopover(false);
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getMessageList();
|
getMessageList();
|
||||||
}, [selectedModel]);
|
}, [selectedModel]);
|
||||||
@@ -45,21 +53,26 @@ const Playground: React.FC = () => {
|
|||||||
onChange={handleSelectChange}
|
onChange={handleSelectChange}
|
||||||
variant="filled"
|
variant="filled"
|
||||||
></Select>
|
></Select>
|
||||||
<SealPopover
|
<Popover
|
||||||
content={<ParamsSettings></ParamsSettings>}
|
content={
|
||||||
|
<ParamsSettings onClose={handleClosePopover}></ParamsSettings>
|
||||||
|
}
|
||||||
destroyTooltipOnHide={true}
|
destroyTooltipOnHide={true}
|
||||||
title="Params Settings"
|
title="Params Settings"
|
||||||
trigger="click"
|
trigger="click"
|
||||||
arrow={false}
|
arrow={false}
|
||||||
overlayInnerStyle={{ maxHeight: '500px', overflow: 'auto' }}
|
open={showPopover}
|
||||||
|
overlayStyle={{ top: 70 }}
|
||||||
|
overlayInnerStyle={{ paddingRight: 0 }}
|
||||||
placement="bottomRight"
|
placement="bottomRight"
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
|
onClick={handleTogglePopover}
|
||||||
type="primary"
|
type="primary"
|
||||||
shape="circle"
|
shape="circle"
|
||||||
icon={<ControlOutlined />}
|
icon={<ControlOutlined />}
|
||||||
></Button>
|
></Button>
|
||||||
</SealPopover>
|
</Popover>
|
||||||
</Space>
|
</Space>
|
||||||
]}
|
]}
|
||||||
footer={[<MessageInput />]}
|
footer={[<MessageInput />]}
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
export const isNotEmptyValue = (value: any) => {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
return value.length > 0;
|
||||||
|
}
|
||||||
|
return value !== null && value !== undefined && value !== '';
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user