feat: add input into schema component (#158)

* feat: add Input Component to schema compoennt

* code cleanup

Co-authored-by: chenos <chenlinxh@gmail.com>
This commit is contained in:
SemmyWong 2022-01-17 16:14:09 +08:00 committed by GitHub
parent e40565e90a
commit 150deb28c1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 281 additions and 0 deletions

View File

@ -6,4 +6,5 @@ export * from './dnd-context';
export * from './form';
export * from './form-item';
export * from './grid';
export * from './input';
export * from './radio';

View File

@ -0,0 +1,28 @@
import React from 'react';
import { Input as AntdInput } from 'antd';
import { InputProps, TextAreaProps } from 'antd/lib/input';
import { connect, mapProps, mapReadPretty } from '@formily/react';
import { LoadingOutlined } from '@ant-design/icons';
import { ReadPretty } from './ReadPretty';
type ComposedInput = React.FC<InputProps> & {
TextArea?: React.FC<TextAreaProps>;
URL?: React.FC<InputProps>;
DesignableBar?: React.FC<any>;
};
export const Input: ComposedInput = connect(
AntdInput,
mapProps((props, field) => {
return {
...props,
suffix: <span>{field?.['loading'] || field?.['validating'] ? <LoadingOutlined /> : props.suffix}</span>,
};
}),
mapReadPretty(ReadPretty.Input),
);
Input.TextArea = connect(AntdInput.TextArea, mapReadPretty(ReadPretty.TextArea));
Input.URL = connect(AntdInput, mapReadPretty(ReadPretty.URL));
export default Input;

View File

@ -0,0 +1,92 @@
import { usePrefixCls } from '@formily/antd/esm/__builtins__';
import { Popover } from 'antd';
import { InputProps, TextAreaProps } from 'antd/lib/input';
import cls from 'classnames';
import React, { useEffect, useState } from 'react';
import { useCompile } from '../../hooks/useCompile';
type Composed = {
Input: React.FC<InputProps & { ellipsis?: any }>;
URL: React.FC<InputProps>;
TextArea: React.FC<TextAreaProps & { ellipsis?: any; text?: any; addonBefore?: any; suffix?: any; addonAfter?: any }>;
};
export const ReadPretty: Composed = () => null;
ReadPretty.Input = (props) => {
const prefixCls = usePrefixCls('description-input', props);
const domRef = React.useRef<HTMLInputElement>(null);
const compile = useCompile();
const [ellipsis, setEllipsis] = useState(false);
const content = compile(props.value);
const ellipsisContent = (
<Popover content={content} style={{ width: 100 }}>
<span className={'input-ellipsis'}>{content}</span>
</Popover>
);
useEffect(() => {
if (domRef.current?.scrollWidth > domRef.current?.clientWidth) {
setEllipsis(true);
}
}, []);
return (
<div className={cls(prefixCls, props.className)} style={props.style}>
{props.addonBefore}
{props.prefix}
<span ref={domRef}>{ellipsis ? ellipsisContent : content}</span>
{props.suffix}
{props.addonAfter}
</div>
);
};
ReadPretty.TextArea = (props) => {
const prefixCls = usePrefixCls('description-textarea', props);
const domRef = React.useRef<HTMLInputElement>(null);
const [ellipsis, setEllipsis] = useState(false);
const ellipsisProp = props.ellipsis === true ? {} : props.ellipsis;
const ellipsisContent = (
<Popover content={props.value}>
<span
className={'input-ellipsis'}
style={{
...ellipsisProp,
}}
>
{props.text || props.value}
</span>
</Popover>
);
useEffect(() => {
if (domRef.current?.scrollWidth > domRef.current?.clientWidth) {
setEllipsis(true);
}
}, []);
return (
<div className={cls(prefixCls, props.className)} style={props.style}>
{props.addonBefore}
{props.prefix}
<span ref={domRef}>{ellipsis ? ellipsisContent : props.value}</span>
{props.suffix}
{props.addonAfter}
</div>
);
};
ReadPretty.URL = (props) => {
const prefixCls = usePrefixCls('description-url', props);
const content = props.value && (
<a target={'_blank'} href={props.value as any}>
{props.value}
</a>
);
return (
<div className={cls(prefixCls, props.className)} style={props.style}>
{props.addonBefore}
{props.prefix}
{content}
{props.suffix}
{props.addonAfter}
</div>
);
};

View File

@ -0,0 +1,41 @@
/**
* title: Input
*/
import { FormItem } from '@formily/antd';
import { Input, SchemaComponent, SchemaComponentProvider } from '@nocobase/client';
import React from 'react';
const schema = {
type: 'object',
properties: {
input: {
type: 'boolean',
title: `Editable`,
'x-decorator': 'FormItem',
'x-component': 'Input',
'x-reactions': {
target: 'read',
fulfill: {
state: {
value: '{{$self.value}}',
},
},
},
},
read: {
type: 'boolean',
title: `Read pretty`,
'x-read-pretty': true,
'x-decorator': 'FormItem',
'x-component': 'Input',
},
},
};
export default () => {
return (
<SchemaComponentProvider components={{ Input, FormItem }}>
<SchemaComponent schema={schema} />
</SchemaComponentProvider>
);
};

View File

@ -0,0 +1,55 @@
/**
* title: Textarea
*/
import { FormItem } from '@formily/antd';
import { Input, SchemaComponent, SchemaComponentProvider } from '@nocobase/client';
import React from 'react';
const schema = {
type: 'object',
properties: {
input: {
interface: 'string',
type: 'string',
title: `Editable`,
name: 'name1',
'x-decorator': 'FormItem',
'x-component': 'Input.TextArea',
'x-reactions': {
target: '*(read1,read2)',
fulfill: {
state: {
value: '{{$self.value}}',
},
},
},
},
read1: {
interface: 'string',
type: 'string',
title: `Read pretty`,
'x-read-pretty': true,
'x-decorator': 'FormItem',
'x-component': 'Input.TextArea',
},
read2: {
interface: 'string',
type: 'string',
title: `Read pretty(ellipsis)`,
'x-read-pretty': true,
'x-decorator': 'FormItem',
'x-component': 'Input.TextArea',
'x-component-props': {
ellipsis: true,
},
},
},
};
export default () => {
return (
<SchemaComponentProvider components={{ Input, FormItem }}>
<SchemaComponent schema={schema} />
</SchemaComponentProvider>
);
};

View File

@ -0,0 +1,43 @@
/**
* title: URL
*/
import { FormItem } from '@formily/antd';
import { Input, SchemaComponent, SchemaComponentProvider } from '@nocobase/client';
import React from 'react';
const schema = {
type: 'object',
properties: {
input: {
type: 'string',
title: `Editable`,
'x-decorator': 'FormItem',
'x-component': 'Input.URL',
'x-validator': 'url',
'x-reactions': {
target: 'read',
fulfill: {
state: {
value: '{{$self.value}}',
},
},
},
},
read: {
type: 'string',
title: `Read pretty`,
'x-read-pretty': true,
'x-decorator': 'FormItem',
'x-component': 'Input.URL',
'x-validator': 'url',
},
},
};
export default () => {
return (
<SchemaComponentProvider components={{ Input, FormItem }}>
<SchemaComponent schema={schema} />
</SchemaComponentProvider>
);
};

View File

@ -6,3 +6,23 @@ group:
---
# Input
## Nodes
- Input
- Input.TextArea
- Input.URL
## Examples
### Input
<code src="./demos/demo1.tsx" />
### Textarea
<code src="./demos/demo2.tsx" />
### URL
<code src="./demos/demo3.tsx" />

View File

@ -0,0 +1 @@
export * from './Input';