diff --git a/packages/client/src/schema-component/antd/index.ts b/packages/client/src/schema-component/antd/index.ts index 8520f1ccb..1fd0a5b8e 100644 --- a/packages/client/src/schema-component/antd/index.ts +++ b/packages/client/src/schema-component/antd/index.ts @@ -6,4 +6,5 @@ export * from './dnd-context'; export * from './form'; export * from './form-item'; export * from './grid'; +export * from './input'; export * from './radio'; diff --git a/packages/client/src/schema-component/antd/input/Input.tsx b/packages/client/src/schema-component/antd/input/Input.tsx new file mode 100644 index 000000000..b0431a9b9 --- /dev/null +++ b/packages/client/src/schema-component/antd/input/Input.tsx @@ -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 & { + TextArea?: React.FC; + URL?: React.FC; + DesignableBar?: React.FC; +}; + +export const Input: ComposedInput = connect( + AntdInput, + mapProps((props, field) => { + return { + ...props, + suffix: {field?.['loading'] || field?.['validating'] ? : props.suffix}, + }; + }), + mapReadPretty(ReadPretty.Input), +); + +Input.TextArea = connect(AntdInput.TextArea, mapReadPretty(ReadPretty.TextArea)); +Input.URL = connect(AntdInput, mapReadPretty(ReadPretty.URL)); + +export default Input; diff --git a/packages/client/src/schema-component/antd/input/ReadPretty.tsx b/packages/client/src/schema-component/antd/input/ReadPretty.tsx new file mode 100644 index 000000000..5dc9e2e48 --- /dev/null +++ b/packages/client/src/schema-component/antd/input/ReadPretty.tsx @@ -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; + URL: React.FC; + TextArea: React.FC; +}; + +export const ReadPretty: Composed = () => null; + +ReadPretty.Input = (props) => { + const prefixCls = usePrefixCls('description-input', props); + const domRef = React.useRef(null); + const compile = useCompile(); + const [ellipsis, setEllipsis] = useState(false); + const content = compile(props.value); + const ellipsisContent = ( + + {content} + + ); + useEffect(() => { + if (domRef.current?.scrollWidth > domRef.current?.clientWidth) { + setEllipsis(true); + } + }, []); + return ( +
+ {props.addonBefore} + {props.prefix} + {ellipsis ? ellipsisContent : content} + {props.suffix} + {props.addonAfter} +
+ ); +}; + +ReadPretty.TextArea = (props) => { + const prefixCls = usePrefixCls('description-textarea', props); + const domRef = React.useRef(null); + const [ellipsis, setEllipsis] = useState(false); + const ellipsisProp = props.ellipsis === true ? {} : props.ellipsis; + const ellipsisContent = ( + + + {props.text || props.value} + + + ); + useEffect(() => { + if (domRef.current?.scrollWidth > domRef.current?.clientWidth) { + setEllipsis(true); + } + }, []); + return ( +
+ {props.addonBefore} + {props.prefix} + {ellipsis ? ellipsisContent : props.value} + {props.suffix} + {props.addonAfter} +
+ ); +}; + +ReadPretty.URL = (props) => { + const prefixCls = usePrefixCls('description-url', props); + const content = props.value && ( + + {props.value} + + ); + return ( +
+ {props.addonBefore} + {props.prefix} + {content} + {props.suffix} + {props.addonAfter} +
+ ); +}; diff --git a/packages/client/src/schema-component/antd/input/demos/demo1.tsx b/packages/client/src/schema-component/antd/input/demos/demo1.tsx new file mode 100644 index 000000000..11c9745c2 --- /dev/null +++ b/packages/client/src/schema-component/antd/input/demos/demo1.tsx @@ -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 ( + + + + ); +}; diff --git a/packages/client/src/schema-component/antd/input/demos/demo2.tsx b/packages/client/src/schema-component/antd/input/demos/demo2.tsx new file mode 100644 index 000000000..1287bb838 --- /dev/null +++ b/packages/client/src/schema-component/antd/input/demos/demo2.tsx @@ -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 ( + + + + ); +}; diff --git a/packages/client/src/schema-component/antd/input/demos/demo3.tsx b/packages/client/src/schema-component/antd/input/demos/demo3.tsx new file mode 100644 index 000000000..39954d27d --- /dev/null +++ b/packages/client/src/schema-component/antd/input/demos/demo3.tsx @@ -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 ( + + + + ); +}; diff --git a/packages/client/src/schema-component/antd/input/index.md b/packages/client/src/schema-component/antd/input/index.md index a957461fb..affbf75b2 100644 --- a/packages/client/src/schema-component/antd/input/index.md +++ b/packages/client/src/schema-component/antd/input/index.md @@ -6,3 +6,23 @@ group: --- # Input + +## Nodes + +- Input +- Input.TextArea +- Input.URL + +## Examples + +### Input + + + +### Textarea + + + +### URL + + diff --git a/packages/client/src/schema-component/antd/input/index.ts b/packages/client/src/schema-component/antd/input/index.ts new file mode 100644 index 000000000..ba9fe7ebc --- /dev/null +++ b/packages/client/src/schema-component/antd/input/index.ts @@ -0,0 +1 @@ +export * from './Input';