feat: manually mirror opencoze's code from bytedance
Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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 { connect, mapProps } from '@formily/react';
|
||||
|
||||
import { FileUpload as FileUploadAdapter } from '../../file-upload';
|
||||
|
||||
export const FileUpload = connect(
|
||||
FileUploadAdapter,
|
||||
mapProps({ validateStatus: true }),
|
||||
);
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { FileUpload } from './file-upload';
|
||||
@@ -0,0 +1,49 @@
|
||||
.form-item {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.form-item-label {
|
||||
margin-bottom: 4px;
|
||||
font-size: 12px;
|
||||
overflow-wrap: break-word;
|
||||
|
||||
.form-item-label-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.top-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.tag {
|
||||
flex-shrink: 0;
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
.label-tooltip {
|
||||
color: var(--coz-fg-secondary);
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.form-item-label-text {
|
||||
font-weight: 500;
|
||||
color: #1D1C23;
|
||||
}
|
||||
|
||||
.form-item-label-asterisk {
|
||||
color: var(--coz-fg-hglt-red);
|
||||
}
|
||||
|
||||
.form-item-feedback-wrap {
|
||||
min-height: 16px;
|
||||
margin-top: 4px;
|
||||
line-height: 16px;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
.form-item-feedback-text {
|
||||
color: var(--coz-fg-hglt-red);
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* test run test form 布局的 FormItem
|
||||
*/
|
||||
import React, { type FC, type ReactNode, type PropsWithChildren } from 'react';
|
||||
|
||||
import { connect, mapProps } from '@formily/react';
|
||||
import { isDataField } from '@formily/core';
|
||||
import { IconCozInfoCircle } from '@coze-arch/coze-design/icons';
|
||||
import { Tooltip, Typography, Tag } from '@coze-arch/coze-design';
|
||||
|
||||
import styles from './index.module.less';
|
||||
|
||||
export interface FormItemProps {
|
||||
required?: boolean;
|
||||
label?: ReactNode;
|
||||
description?: ReactNode;
|
||||
tag?: ReactNode;
|
||||
tooltip?: ReactNode;
|
||||
feedbackText?: ReactNode;
|
||||
action?: ReactNode;
|
||||
}
|
||||
|
||||
export const FormItemAdapter: FC<PropsWithChildren<FormItemProps>> = props => {
|
||||
const {
|
||||
required,
|
||||
label,
|
||||
feedbackText,
|
||||
description,
|
||||
tooltip,
|
||||
tag,
|
||||
action,
|
||||
children,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div className={styles['form-item']}>
|
||||
<div className={styles['form-item-label']}>
|
||||
<div className={styles['form-item-label-top']}>
|
||||
<div className={styles['top-left']}>
|
||||
<span className={styles['form-item-label-text']}>{label}</span>
|
||||
{required ? (
|
||||
<span className={styles['form-item-label-asterisk']}>*</span>
|
||||
) : null}
|
||||
{tooltip ? (
|
||||
<Tooltip content={tooltip}>
|
||||
<IconCozInfoCircle className={styles['label-tooltip']} />
|
||||
</Tooltip>
|
||||
) : null}
|
||||
|
||||
{tag ? (
|
||||
<Tag className={styles.tag} size="mini" color="primary">
|
||||
{tag}
|
||||
</Tag>
|
||||
) : null}
|
||||
</div>
|
||||
{action}
|
||||
</div>
|
||||
{description ? (
|
||||
<Typography.Text
|
||||
size="small"
|
||||
type="secondary"
|
||||
ellipsis={{
|
||||
showTooltip: true,
|
||||
}}
|
||||
>
|
||||
{description}
|
||||
</Typography.Text>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
<div>{children}</div>
|
||||
{feedbackText ? (
|
||||
<div className={styles['form-item-feedback-wrap']}>
|
||||
<Typography.Text
|
||||
size="small"
|
||||
className={styles['form-item-feedback-text']}
|
||||
>
|
||||
{feedbackText}
|
||||
</Typography.Text>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const FormItem = connect(
|
||||
FormItemAdapter,
|
||||
mapProps(
|
||||
{
|
||||
title: 'label',
|
||||
required: true,
|
||||
tag: true,
|
||||
description: true,
|
||||
} as any,
|
||||
(props, field) => ({
|
||||
...props,
|
||||
feedbackText:
|
||||
isDataField(field) && field.selfErrors?.length
|
||||
? field.selfErrors
|
||||
: undefined,
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
export { FormItem };
|
||||
@@ -0,0 +1,41 @@
|
||||
.form-section :global .coz-icon-button-mini {
|
||||
line-height: 0px;
|
||||
}
|
||||
|
||||
.form-section {
|
||||
border-bottom: 1px solid var(--coz-stroke-primary);
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 10px 16px 10px 2px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
column-gap: 4px;
|
||||
cursor: pointer;
|
||||
|
||||
.title-collapsible {
|
||||
color: var(--coz-fg-secondary);
|
||||
font-size: 12px;
|
||||
margin-right: -2px;
|
||||
}
|
||||
|
||||
.is-close {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
.title-tooltip {
|
||||
font-size: 14px;
|
||||
color: var(--coz-fg-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.section-context {
|
||||
padding: 0 16px 10px 16px ;
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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, { useState } from 'react';
|
||||
|
||||
import cls from 'classnames';
|
||||
import {
|
||||
IconCozArrowDownFill,
|
||||
IconCozInfoCircle,
|
||||
} from '@coze-arch/coze-design/icons';
|
||||
import { Collapsible, Tooltip, Typography } from '@coze-arch/coze-design';
|
||||
|
||||
import css from './index.module.less';
|
||||
|
||||
export interface FormSectionProps {
|
||||
title?: React.ReactNode;
|
||||
tooltip?: React.ReactNode;
|
||||
action?: React.ReactNode;
|
||||
collapsible?: boolean;
|
||||
}
|
||||
|
||||
export const FormSection: React.FC<
|
||||
React.PropsWithChildren<FormSectionProps>
|
||||
> = ({ title, tooltip, action, collapsible, children }) => {
|
||||
const [isOpen, setIsOpen] = useState(true);
|
||||
|
||||
const handleExpand = () => {
|
||||
setIsOpen(!isOpen);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={css['form-section']}>
|
||||
<div className={css['section-header']}>
|
||||
<div
|
||||
className={css['section-title']}
|
||||
onClick={collapsible ? handleExpand : undefined}
|
||||
>
|
||||
{collapsible ? (
|
||||
<IconCozArrowDownFill
|
||||
className={cls(css['title-collapsible'], {
|
||||
[css['is-close']]: !isOpen,
|
||||
})}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
<Typography.Text strong>{title}</Typography.Text>
|
||||
|
||||
{tooltip ? (
|
||||
<Tooltip content={tooltip}>
|
||||
<IconCozInfoCircle className={css['title-tooltip']} />
|
||||
</Tooltip>
|
||||
) : null}
|
||||
</div>
|
||||
{action ? (
|
||||
<div
|
||||
className={css['section-action']}
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
{action}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
<Collapsible keepDOM fade isOpen={isOpen}>
|
||||
<div className={css['section-context']}>{children}</div>
|
||||
</Collapsible>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
.full-input :global {
|
||||
.editor-kit-toolbar-v2-wrapper {
|
||||
padding: 0 2px;
|
||||
|
||||
button {
|
||||
margin: 0 2px;
|
||||
}
|
||||
}
|
||||
.editor-kit-container {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.full-input {
|
||||
min-height: 120px;
|
||||
border: 1px solid var(--coz-stroke-plus);
|
||||
}
|
||||
|
||||
.modal-full-input {
|
||||
min-height: 570px;
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
/*
|
||||
* 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 { useState, useEffect, useRef, Suspense } from 'react';
|
||||
|
||||
import { nanoid } from 'nanoid';
|
||||
import cls from 'classnames';
|
||||
import { connect, mapProps } from '@formily/react';
|
||||
import type { Editor } from '@coze-common/md-editor-adapter';
|
||||
import {
|
||||
delta2md,
|
||||
md2html,
|
||||
LazyEditorFullInputInner,
|
||||
ToolbarItemEnum,
|
||||
} from '@coze-common/md-editor-adapter';
|
||||
import { Modal } from '@coze-arch/coze-design';
|
||||
|
||||
import css from './full-input.module.less';
|
||||
|
||||
export interface InnerFullInputProps {
|
||||
value?: string;
|
||||
disabled?: boolean;
|
||||
/** 是否可以展开,默认 true */
|
||||
expand?: boolean;
|
||||
className?: string;
|
||||
onChange: (v?: string) => void;
|
||||
onExpand?: () => void;
|
||||
}
|
||||
|
||||
export type FullInputProps = InnerFullInputProps & {
|
||||
modalTitle?: string;
|
||||
};
|
||||
|
||||
const InnerFullInputAdapter: React.FC<FullInputProps> = ({
|
||||
className,
|
||||
disabled,
|
||||
expand = true,
|
||||
value,
|
||||
onChange,
|
||||
...props
|
||||
}) => {
|
||||
const editorRef = useRef<Editor | null>(null);
|
||||
const businessKeyRef = useRef(nanoid());
|
||||
const innerValueRef = useRef<string | undefined>();
|
||||
|
||||
const handleChange = (v: string) => {
|
||||
if (!editorRef.current) {
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* deltas => md
|
||||
*/
|
||||
const content = editorRef.current.getContent();
|
||||
const { markdown } = delta2md(content.deltas[0], content.deltas);
|
||||
/**
|
||||
* change 可能来自用户输入或者初始化,做一下 diff 来保证性能
|
||||
*/
|
||||
if (markdown !== innerValueRef.current) {
|
||||
innerValueRef.current = markdown;
|
||||
onChange(markdown);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (value !== innerValueRef.current) {
|
||||
innerValueRef.current = value || '';
|
||||
/**
|
||||
* md => html
|
||||
*/
|
||||
editorRef.current?.setHTML(md2html(value || ''));
|
||||
}
|
||||
}, [value]);
|
||||
|
||||
return (
|
||||
<Suspense fallback={null}>
|
||||
<LazyEditorFullInputInner
|
||||
field="full-input"
|
||||
className={cls(css['full-input'], className)}
|
||||
businessKey={businessKeyRef.current}
|
||||
noToolbar={disabled}
|
||||
noExpand={!expand}
|
||||
getEditor={editor => {
|
||||
editorRef.current = editor;
|
||||
}}
|
||||
disabled={disabled}
|
||||
onChange={handleChange}
|
||||
registerToolItem={items =>
|
||||
items
|
||||
.filter(i => (i as any)?.type !== ToolbarItemEnum.Image)
|
||||
.map(i => {
|
||||
const item = i as any;
|
||||
if (item?.type && item.extraPropsToBuiltinComp) {
|
||||
item.extraPropsToBuiltinComp = {
|
||||
...item.extraPropsToBuiltinComp,
|
||||
size: 'extra-small',
|
||||
};
|
||||
}
|
||||
return item;
|
||||
})
|
||||
}
|
||||
{...props}
|
||||
/>
|
||||
</Suspense>
|
||||
);
|
||||
};
|
||||
|
||||
const FullInputAdapter: React.FC<FullInputProps> = ({
|
||||
expand,
|
||||
modalTitle,
|
||||
...props
|
||||
}) => {
|
||||
const [modalVisible, setModalVisible] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Modal
|
||||
visible={modalVisible}
|
||||
centered
|
||||
title={modalTitle}
|
||||
onCancel={() => setModalVisible(false)}
|
||||
>
|
||||
<InnerFullInputAdapter
|
||||
expand={false}
|
||||
className={css['modal-full-input']}
|
||||
{...props}
|
||||
/>
|
||||
</Modal>
|
||||
<InnerFullInputAdapter
|
||||
expand={expand}
|
||||
onExpand={() => setModalVisible(true)}
|
||||
{...props}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const FullInput = connect(
|
||||
FullInputAdapter,
|
||||
mapProps({ validateStatus: true }),
|
||||
);
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { FullInput } from './full-input';
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// components
|
||||
export { Input } from './input';
|
||||
export { FileUpload } from './file-upload';
|
||||
export { Switch } from './switch';
|
||||
export { InputInteger, InputNumber } from './input-number';
|
||||
export { VoiceSelect } from './voice-select';
|
||||
export { TextArea } from './text-area';
|
||||
export { FullInput } from './full-input';
|
||||
// decorators
|
||||
export { FormItem } from './form-item';
|
||||
export { FormSection } from './form-section';
|
||||
export { InputTime } from './input-time';
|
||||
@@ -0,0 +1,26 @@
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
.button {
|
||||
font-size: 12px;
|
||||
color: rgba(var(--coze-fg-3), var(--coze-fg-3-alpha));
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background-color: rgba(var(--coze-bg-5), var(--coze-bg-5-alpha));
|
||||
}
|
||||
&.up {
|
||||
border-top-left-radius: var(--coze-5);
|
||||
border-top-right-radius: var(--coze-5);
|
||||
}
|
||||
&.down {
|
||||
border-bottom-left-radius: var(--coze-5);
|
||||
border-bottom-right-radius: var(--coze-5);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* 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 { useRef, useMemo, useEffect } from 'react';
|
||||
|
||||
import cls from 'classnames';
|
||||
import BigNumber, { type BigNumber as IBigNumber } from 'bignumber.js';
|
||||
import {
|
||||
IconCozArrowDown,
|
||||
IconCozArrowUp,
|
||||
} from '@coze-arch/coze-design/icons';
|
||||
import { Input, type InputProps } from '@coze-arch/coze-design';
|
||||
|
||||
import css from './base-input-number-v2.module.less';
|
||||
|
||||
export interface InputNumberV2Props {
|
||||
value?: string;
|
||||
style?: React.CSSProperties;
|
||||
placeholder?: string;
|
||||
validateStatus?: InputProps['validateStatus'];
|
||||
disabled?: boolean;
|
||||
'data-testid'?: string;
|
||||
onChange?: (v?: string) => void;
|
||||
onBlur?: () => void;
|
||||
onFocus?: () => void;
|
||||
/** 整型 */
|
||||
int?: boolean;
|
||||
}
|
||||
|
||||
/** 是否是合法的数字字符串 */
|
||||
function isValidNumber(str: string) {
|
||||
try {
|
||||
const value = new BigNumber(str);
|
||||
return !value.isNaN();
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeNumber(str?: string) {
|
||||
if (!str || !isValidNumber(str)) {
|
||||
return;
|
||||
}
|
||||
return new BigNumber(str);
|
||||
}
|
||||
|
||||
export const InputNumberV2Adapter: React.FC<InputNumberV2Props> = ({
|
||||
int,
|
||||
onChange,
|
||||
onBlur,
|
||||
...props
|
||||
}) => {
|
||||
const isShowButtons = useMemo(() => !props.disabled, [props.disabled]);
|
||||
const verifiedRef = useRef<undefined | IBigNumber>(
|
||||
normalizeNumber(props.value),
|
||||
);
|
||||
|
||||
const fixed = (num: IBigNumber, innerInt?: boolean) =>
|
||||
innerInt ? num.toFixed(0, BigNumber.ROUND_DOWN) : num.toFixed();
|
||||
|
||||
const handleBlur = () => {
|
||||
if (props.value === '' || props.value === undefined) {
|
||||
/** 失焦时若值为空,则同时清空验证值 */
|
||||
verifiedRef.current = undefined;
|
||||
if (props.value === '') {
|
||||
// 如果是空字符串需要主动转换为 undefined
|
||||
onChange?.(undefined);
|
||||
}
|
||||
} else {
|
||||
/** 失焦时若值不为空,则需要验证值的合法性 */
|
||||
/**
|
||||
* 1. 若值本身合法,则对值做格式化
|
||||
* 2. 若值不合法,则采纳最近一次的合法值
|
||||
* 3. 若都没有,则返回 undefined
|
||||
*/
|
||||
let next: undefined | string;
|
||||
const nextBig = normalizeNumber(props.value) || verifiedRef.current;
|
||||
if (nextBig) {
|
||||
next = fixed(nextBig, int);
|
||||
}
|
||||
if (next !== props.value) {
|
||||
onChange?.(next);
|
||||
}
|
||||
}
|
||||
onBlur?.();
|
||||
};
|
||||
|
||||
const handlePlus = () => {
|
||||
let next = '1';
|
||||
if (verifiedRef.current) {
|
||||
const nextNum = verifiedRef.current.plus('1');
|
||||
next = fixed(nextNum, int);
|
||||
}
|
||||
onChange?.(next);
|
||||
};
|
||||
|
||||
const handleMinus = () => {
|
||||
let next = '0';
|
||||
if (verifiedRef.current) {
|
||||
const nextNum = verifiedRef.current.minus('1');
|
||||
next = fixed(nextNum, int);
|
||||
}
|
||||
onChange?.(next);
|
||||
};
|
||||
|
||||
/** 当值发生变化,需要把值同步到合法数字 */
|
||||
useEffect(() => {
|
||||
if (props.value === '' || props.value === undefined) {
|
||||
verifiedRef.current = undefined;
|
||||
}
|
||||
const next = normalizeNumber(props.value);
|
||||
if (next) {
|
||||
verifiedRef.current = normalizeNumber(props.value);
|
||||
}
|
||||
}, [props.value]);
|
||||
|
||||
return (
|
||||
<Input
|
||||
onChange={onChange}
|
||||
onBlur={handleBlur}
|
||||
suffix={
|
||||
<div className={css.buttons}>
|
||||
<div className={cls(css.button, css.up)} onClick={handlePlus}>
|
||||
<IconCozArrowUp />
|
||||
</div>
|
||||
<div className={cls(css.button, css.down)} onClick={handleMinus}>
|
||||
<IconCozArrowDown />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
hideSuffix={!isShowButtons}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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 { useCallback } from 'react';
|
||||
|
||||
import { CozInputNumber, type InputNumberProps } from '@coze-arch/coze-design';
|
||||
|
||||
export type BaseInputNumberAdapterProps = {
|
||||
value?: number | string;
|
||||
onChange?: (v?: number | string) => void;
|
||||
} & Pick<InputNumberProps, 'precision'>;
|
||||
|
||||
export const BaseInputNumberAdapter: React.FC<BaseInputNumberAdapterProps> = ({
|
||||
onChange,
|
||||
...props
|
||||
}) => {
|
||||
const handleChange = useCallback(
|
||||
(v: number | string) => {
|
||||
onChange?.(v === '' ? undefined : v);
|
||||
},
|
||||
[onChange],
|
||||
);
|
||||
return (
|
||||
<CozInputNumber
|
||||
onChange={handleChange}
|
||||
{...props}
|
||||
size="small"
|
||||
style={{ width: '100%' }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { InputInteger } from './input-integer';
|
||||
export { InputNumber } from './input-number';
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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 { connect } from '@formily/react';
|
||||
|
||||
import {
|
||||
BaseInputNumberAdapter,
|
||||
type BaseInputNumberAdapterProps,
|
||||
} from './base-input-number';
|
||||
|
||||
const InputIntegerAdapter: React.FC<BaseInputNumberAdapterProps> = props => (
|
||||
<BaseInputNumberAdapter {...props} precision={0.1} />
|
||||
);
|
||||
|
||||
export const InputInteger = connect(InputIntegerAdapter);
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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 { connect } from '@formily/react';
|
||||
|
||||
import { BaseInputNumberAdapter } from './base-input-number';
|
||||
|
||||
export const InputNumber = connect(BaseInputNumberAdapter);
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { InputTime, type InputTimeProps } from './time';
|
||||
@@ -0,0 +1,6 @@
|
||||
.input-time {
|
||||
width: 100%;
|
||||
:global .semi-select {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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 cls from 'classnames';
|
||||
import { DatePicker } from '@coze-arch/coze-design';
|
||||
|
||||
import css from './time.module.less';
|
||||
|
||||
export interface InputTimeProps {
|
||||
className?: string;
|
||||
value?: string;
|
||||
onChange?: (v?: string) => void;
|
||||
}
|
||||
|
||||
export const InputTime: React.FC<InputTimeProps> = ({
|
||||
className,
|
||||
value,
|
||||
onChange,
|
||||
...props
|
||||
}) => (
|
||||
<DatePicker
|
||||
className={cls(css['input-time'], className)}
|
||||
type="dateTime"
|
||||
size="small"
|
||||
showClear={false}
|
||||
showSuffix={false}
|
||||
value={value}
|
||||
onChange={(_date, dateString) => {
|
||||
if (typeof dateString === 'string' || dateString === undefined) {
|
||||
onChange?.(dateString);
|
||||
}
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { Input } from './input';
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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 { connect, mapProps } from '@formily/react';
|
||||
import { Input as InputCore } from '@coze-arch/coze-design';
|
||||
|
||||
const InputAdapter = props => <InputCore size="small" {...props} />;
|
||||
|
||||
export const Input = connect(InputAdapter, mapProps({ validateStatus: true }));
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { Switch } from './switch';
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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 { connect } from '@formily/react';
|
||||
import { Switch as CozSwitch } from '@coze-arch/coze-design';
|
||||
|
||||
export interface SwitchProps {
|
||||
value?: boolean;
|
||||
onChange?: (v: boolean) => void;
|
||||
}
|
||||
|
||||
const SwitchAdapter: React.FC<SwitchProps> = ({ value, ...props }) => (
|
||||
<CozSwitch checked={value} {...props} size="small" />
|
||||
);
|
||||
|
||||
export const Switch = connect(SwitchAdapter);
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { TextArea } from './text-area';
|
||||
@@ -0,0 +1,6 @@
|
||||
.text-area-small {
|
||||
textarea {
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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 cls from 'classnames';
|
||||
import { connect, mapProps } from '@formily/react';
|
||||
import { TextArea as TextAreaCore } from '@coze-arch/coze-design';
|
||||
|
||||
import css from './text-area.module.less';
|
||||
|
||||
export interface TextAreaProps {
|
||||
size?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const TextAreaAdapter: React.FC<TextAreaProps> = ({
|
||||
size,
|
||||
className,
|
||||
...props
|
||||
}) => (
|
||||
<TextAreaCore
|
||||
className={cls(
|
||||
{
|
||||
[css['text-area-small']]: size === 'small',
|
||||
},
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
export const TextArea = connect(
|
||||
TextAreaAdapter,
|
||||
mapProps({ validateStatus: true }),
|
||||
);
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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 { connect, mapProps } from '@formily/react';
|
||||
import { VoiceSelect as VoiceSelectBase } from '@coze-workflow/components';
|
||||
|
||||
const VoiceSelectAdapter = props => <VoiceSelectBase {...props} />;
|
||||
|
||||
export const VoiceSelect = connect(
|
||||
VoiceSelectAdapter,
|
||||
mapProps({ validateStatus: true }),
|
||||
);
|
||||
Reference in New Issue
Block a user