style: form item style

This commit is contained in:
jialin
2025-03-25 12:33:29 +08:00
parent dca7a6f270
commit 626e29a001
6 changed files with 31 additions and 442 deletions
@@ -1,69 +0,0 @@
import classNames from 'classnames';
import React from 'react';
import LabelInfo from './components/label-info';
import wrapperStyle from './components/wrapper.less';
interface WrapperProps {
children: React.ReactNode;
label: React.ReactNode;
status?: string;
className?: string;
disabled?: boolean;
required?: boolean;
description?: React.ReactNode;
variant?: string;
style?: React.CSSProperties;
onClick?: () => void;
}
const Wrapper: React.FC<WrapperProps> = ({
children,
label,
status,
className,
disabled,
required,
variant,
style,
description
}) => {
return (
<div
style={{
padding: '0 calc(var(--ant-padding-sm) - 5px)',
width: '100%',
...style
}}
className={classNames(
wrapperStyle.wrapper,
wrapperStyle[`validate-status-${status}`],
disabled ? wrapperStyle['seal-input-wrapper-disabled'] : '',
variant === 'filled' ? wrapperStyle['filled'] : '',
variant === 'borderless' ? wrapperStyle['borderless'] : '',
className ? wrapperStyle[className] : ''
)}
>
<label
className={classNames(
wrapperStyle['label'],
wrapperStyle['isfoucs-has-value']
)}
>
<LabelInfo
label={label}
required={required}
description={description}
></LabelInfo>
</label>
<div
className="child-inner"
style={{
width: '100%'
}}
>
{children}
</div>
</div>
);
};
export default Wrapper;
+24 -21
View File
@@ -1,8 +1,9 @@
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 React, { useEffect, useRef, useState } from 'react';
import { SealFormItemProps } from './types';
import Wrapper from './wrapper';
import InputWrapper from './wrapper/input';
type OnSearch = (
value: string,
@@ -66,25 +67,27 @@ const SealInputSearch: React.FC<SearchProps & SealFormItemProps> = (props) => {
};
return (
<Wrapper
status={status}
label={label}
isFocus={isFocus}
required={required}
description={description}
disabled={props.disabled}
onClick={handleClickWrapper}
>
<Input.Search
{...rest}
ref={inputRef}
autoComplete="off"
onFocus={handleOnFocus}
onBlur={handleOnBlur}
onSearch={handleSearch}
onChange={handleChange}
></Input.Search>
</Wrapper>
<InputWrapper>
<Wrapper
status={status}
label={label}
isFocus={isFocus}
required={required}
description={description}
disabled={props.disabled}
onClick={handleClickWrapper}
>
<Input.Search
{...rest}
ref={inputRef}
autoComplete="off"
onFocus={handleOnFocus}
onBlur={handleOnBlur}
onSearch={handleSearch}
onChange={handleChange}
></Input.Search>
</Wrapper>
</InputWrapper>
);
};
+1 -3
View File
@@ -54,9 +54,7 @@ const SealSlider: React.FC<SealSliderProps> = (props) => {
className="slider-label"
style={{ width: labelWidth || INPUT_WIDTH.mini }}
>
<span className="text">
<LabelInfo label={label} description={description}></LabelInfo>
</span>
<LabelInfo label={label} description={description}></LabelInfo>
{inputnumber ? (
<InputNumber
+1 -1
View File
@@ -109,7 +109,7 @@ const InputWrapper = styled.div`
.ant-input-search-button {
position: absolute;
top: -20px;
right: 0;
right: 1px;
border-radius: 0 ${BORDERRADIUS}px ${BORDERRADIUS}px 0 !important;
overflow: hidden;
border: none;
+5 -1
View File
@@ -2,6 +2,10 @@ import styled from 'styled-components';
import { INPUTHEIGHT, INPUT_INNER_PADDING } from '../config';
const SliderWrapper = styled.div`
.__wrapper__ {
height: 100%;
justify-content: center;
}
padding-block: 0;
padding-inline: 2px;
input.ant-input-number-input {
@@ -24,7 +28,7 @@ const SliderWrapper = styled.div`
.label-val {
position: absolute !important;
top: -14px;
right: -14px;
right: -10px;
width: 80px;
border-radius: var(--border-radius-base);
text-align: center;
@@ -1,347 +0,0 @@
import FieldWrapper from '@/components/seal-form/field-wrapper';
import SealInput from '@/components/seal-form/seal-input';
import SealSelect from '@/components/seal-form/seal-select';
import { INPUT_WIDTH } from '@/constants';
import { QuestionCircleOutlined } from '@ant-design/icons';
import { useIntl } from '@umijs/max';
import { Form, InputNumber, Slider, Tooltip } from 'antd';
import _ from 'lodash';
import { memo, useCallback, useEffect, useId, useState } from 'react';
import CustomLabelStyles from '../style/custom-label.less';
type ParamsSettingsFormProps = {
seed?: number;
stop?: number;
temperature?: number;
top_p?: number;
max_tokens?: number;
model?: string;
};
type ParamsSettingsProps = {
selectedModel?: string;
showModelSelector?: boolean;
params?: ParamsSettingsFormProps;
model?: string;
modelList: Global.BaseOption<string>[];
onValuesChange?: (changeValues: any, value: Record<string, any>) => void;
setParams: (params: any) => void;
globalParams?: ParamsSettingsFormProps;
};
const METAKEYS: Record<string, any> = {
seed: 'seed',
stop: 'stop',
temperature: 'temperature',
top_p: 'top_p',
n_ctx: 'n_ctx',
n_slot: 'n_slot',
max_model_len: 'max_model_len'
};
const ParamsSettings: React.FC<ParamsSettingsProps> = ({
selectedModel,
setParams,
globalParams,
onValuesChange,
modelList,
showModelSelector = true
}) => {
const intl = useIntl();
const initialValues = {
seed: null,
stop: null,
temperature: 1,
top_p: 1,
max_tokens: 1024,
...globalParams
};
const [form] = Form.useForm();
const formId = useId();
const [metaData, setMetaData] = useState<Record<string, any>>({});
const [firstLoad, setFirstLoad] = useState(true);
const handleOnFinish = (values: any) => {
console.log('handleOnFinish', values);
};
const handleOnFinishFailed = (errorInfo: any) => {
console.log('handleOnFinishFailed', errorInfo);
};
const handleValuesChange = useCallback(
(changedValues: any, allValues: any) => {
setParams?.(allValues);
onValuesChange?.(changedValues, allValues);
},
[onValuesChange, setParams]
);
const handleFieldValueChange = useCallback(
(val: any, field: string) => {
const values = form.getFieldsValue();
form.setFieldsValue({
...values,
[field]: val
});
setParams({
...values,
[field]: val
});
onValuesChange?.(
{ [field]: val },
{
...values,
[field]: val
}
);
},
[form, setParams, onValuesChange]
);
const handleModelChange = (val: string) => {
const model = _.find(modelList, { value: val });
const modelMeta = model?.meta || {};
const modelMetaValue = _.pick(modelMeta, _.keys(METAKEYS));
const obj = Object.entries(METAKEYS).reduce((acc: any, [key, value]) => {
const val = modelMetaValue[key];
if (val && _.hasIn(modelMetaValue, key)) {
acc[value] = val;
}
return acc;
}, {});
let defaultMaxTokens = 1024;
if (obj.n_ctx && obj.n_slot) {
defaultMaxTokens = _.divide(obj.n_ctx / 2, obj.n_slot);
} else if (obj.max_model_len) {
defaultMaxTokens = obj.max_model_len / 2;
}
const initials = {
..._.omit(obj, ['n_ctx', 'n_slot', 'max_model_len']),
seed: obj.seed === -1 ? null : obj.seed,
max_tokens: defaultMaxTokens
};
form.setFieldsValue(initials);
setMetaData({
...obj,
max_tokens: obj.max_model_len || _.divide(obj.n_ctx, obj.n_slot)
});
return initials;
};
useEffect(() => {
let model = selectedModel || '';
if (showModelSelector) {
model = model || _.get(modelList, '[0].value');
}
const modelMetaData = handleModelChange(model);
const mergeData = _.merge({}, initialValues, modelMetaData);
form.setFieldsValue({
...mergeData,
model: model
});
setParams({
...mergeData,
model: model
});
setFirstLoad(false);
}, [modelList, showModelSelector, selectedModel]);
useEffect(() => {
if (!firstLoad) {
form.setFieldsValue(globalParams);
}
}, [globalParams, firstLoad]);
const renderLabel = (args: {
field: string;
label: string;
description: string;
}) => {
return (
<span
className={CustomLabelStyles.label}
style={{ width: INPUT_WIDTH.mini }}
>
<span className="text">
{args.description ? (
<Tooltip title={args.description}>
<span> {args.label}</span>
<span className="m-l-5">
<QuestionCircleOutlined />
</span>
</Tooltip>
) : (
<span>{args.label}</span>
)}
</span>
<InputNumber
className="label-val"
variant="outlined"
size="small"
value={form.getFieldValue(args.field)}
controls={false}
onChange={(val) => handleFieldValueChange(val, args.field)}
></InputNumber>
</span>
);
};
return (
<Form
name={formId}
form={form}
onValuesChange={handleValuesChange}
onFinish={handleOnFinish}
onFinishFailed={handleOnFinishFailed}
>
<div>
{showModelSelector && (
<>
<h3 className="m-b-20 m-l-10 font-size-14 line-24">
{intl.formatMessage({ id: 'playground.model' })}
</h3>
<Form.Item<ParamsSettingsFormProps>
name="model"
rules={[
{
required: true,
message: intl.formatMessage(
{
id: 'common.form.rule.select'
},
{ name: intl.formatMessage({ id: 'playground.model' }) }
)
}
]}
>
<SealSelect
showSearch={true}
options={modelList}
onChange={handleModelChange}
></SealSelect>
</Form.Item>
</>
)}
<h3 className="m-b-20 m-l-10 flex-between flex-center font-size-14 line-24">
<span>{intl.formatMessage({ id: 'playground.parameters' })}</span>
</h3>
<Form.Item<ParamsSettingsFormProps>
name="temperature"
rules={[{ required: false }]}
>
<FieldWrapper
label={renderLabel({
field: 'temperature',
label: 'Temperature',
description: intl.formatMessage({
id: 'playground.params.temperature.tips'
})
})}
style={{ padding: '20px 2px 0' }}
variant="borderless"
>
<Slider
defaultValue={1}
max={2}
step={0.1}
style={{ marginBottom: 0, marginTop: 16, marginInline: 0 }}
tooltip={{ open: false }}
value={form.getFieldValue('temperature') || undefined}
onChange={(val) => handleFieldValueChange(val, 'temperature')}
></Slider>
</FieldWrapper>
</Form.Item>
<Form.Item<ParamsSettingsFormProps>
name="max_tokens"
rules={[{ required: false }]}
>
<FieldWrapper
label={renderLabel({
field: 'max_tokens',
label: 'Max Tokens',
description: intl.formatMessage({
id: 'playground.params.maxtokens.tips'
})
})}
style={{ padding: '20px 2px 0' }}
variant="borderless"
>
<Slider
defaultValue={2048}
max={metaData.max_tokens || 16 * 1024}
step={1}
style={{ marginBottom: 0, marginTop: 16, marginInline: 0 }}
tooltip={{ open: false }}
value={form.getFieldValue('max_tokens') || undefined}
onChange={(val) => handleFieldValueChange(val, 'max_tokens')}
></Slider>
</FieldWrapper>
</Form.Item>
<Form.Item<ParamsSettingsFormProps>
name="top_p"
rules={[{ required: false }]}
>
<FieldWrapper
label={renderLabel({
field: 'top_p',
label: 'Top P',
description: intl.formatMessage({
id: 'playground.params.topp.tips'
})
})}
style={{ padding: '20px 2px 0' }}
variant="borderless"
>
<Slider
defaultValue={1}
max={1}
step={0.1}
style={{ marginBottom: 0, marginTop: 16, marginInline: 0 }}
tooltip={{ open: false }}
value={form.getFieldValue('top_p') || undefined}
onChange={(val) => handleFieldValueChange(val, 'top_p')}
></Slider>
</FieldWrapper>
</Form.Item>
<Form.Item<ParamsSettingsFormProps>
name="seed"
rules={[{ required: false }]}
>
<SealInput.Number
label="Seed"
min={0}
description={intl.formatMessage({
id: 'playground.params.seed.tips'
})}
style={{ width: INPUT_WIDTH.mini }}
></SealInput.Number>
</Form.Item>
<Form.Item<ParamsSettingsFormProps>
name="stop"
rules={[{ required: false }]}
normalize={(value) => {
return value || null;
}}
>
<SealInput.Input
allowClear
label="Stop Sequence"
description={intl.formatMessage({
id: 'playground.params.stop.tips'
})}
style={{ width: INPUT_WIDTH.mini }}
></SealInput.Input>
</Form.Item>
</div>
</Form>
);
};
export default memo(ParamsSettings);