129 lines
3.5 KiB
TypeScript
129 lines
3.5 KiB
TypeScript
import React, { useRef, useLayoutEffect } from 'react';
|
|
import { createControllerBox, Schema } from '@formily/react-schema-renderer';
|
|
import { IFormTextBox } from '../types';
|
|
import { toArr } from '@formily/shared';
|
|
import { FormItemProps as ItemProps } from 'antd/lib/form';
|
|
import { version } from 'antd';
|
|
import { AntdSchemaFieldAdaptor, pickFormItemProps } from '@formily/antd';
|
|
import styled from 'styled-components';
|
|
|
|
const isV4 = /^4\./.test(version);
|
|
|
|
export const FormTextBox = createControllerBox<IFormTextBox & ItemProps>(
|
|
'text-box',
|
|
styled(({ props, form, className, children }) => {
|
|
const schema = new Schema(props);
|
|
const mergeProps = schema.getExtendsComponentProps();
|
|
const { title, label, text, gutter, style } = Object.assign(
|
|
{
|
|
gutter: 5,
|
|
},
|
|
mergeProps,
|
|
);
|
|
const formItemProps = pickFormItemProps(mergeProps);
|
|
const ref: React.RefObject<HTMLDivElement> = useRef();
|
|
const arrChildren = toArr(children);
|
|
const split = text.split('%s');
|
|
let index = 0;
|
|
useLayoutEffect(() => {
|
|
if (ref.current) {
|
|
const elements = ref.current.querySelectorAll('.text-box-field');
|
|
const syncLayouts = Array.prototype.map.call(
|
|
elements,
|
|
(el: HTMLElement) => {
|
|
return [
|
|
el,
|
|
() => {
|
|
const ctrl = el.querySelector('.ant-form-item-children');
|
|
setTimeout(() => {
|
|
if (ctrl) {
|
|
const editable = form.getFormState(state => state.editable);
|
|
el.style.width = editable
|
|
? ctrl.getBoundingClientRect().width + 'px'
|
|
: 'auto';
|
|
}
|
|
});
|
|
},
|
|
];
|
|
},
|
|
);
|
|
syncLayouts.forEach(([el, handler]) => {
|
|
handler();
|
|
el.addEventListener('DOMSubtreeModified', handler);
|
|
});
|
|
|
|
return () => {
|
|
syncLayouts.forEach(([el, handler]) => {
|
|
el.removeEventListener('DOMSubtreeModified', handler);
|
|
});
|
|
};
|
|
}
|
|
}, []);
|
|
const newChildren = split.reduce((buf, item, key) => {
|
|
return buf.concat(
|
|
item ? (
|
|
<p
|
|
key={index++}
|
|
className="text-box-words"
|
|
style={{
|
|
marginRight: gutter / 2,
|
|
marginLeft: gutter / 2,
|
|
...style,
|
|
}}
|
|
>
|
|
{item}
|
|
</p>
|
|
) : null,
|
|
arrChildren[key] ? (
|
|
<div key={index++} className="text-box-field">
|
|
{arrChildren[key]}
|
|
</div>
|
|
) : null,
|
|
);
|
|
}, []);
|
|
|
|
const textChildren = (
|
|
<div
|
|
className={`${className} ${mergeProps.className}`}
|
|
style={{
|
|
marginRight: -gutter / 2,
|
|
marginLeft: -gutter / 2,
|
|
}}
|
|
ref={ref}
|
|
>
|
|
{newChildren}
|
|
</div>
|
|
);
|
|
|
|
if (!title && !label) return textChildren;
|
|
return (
|
|
<AntdSchemaFieldAdaptor {...formItemProps}>
|
|
{textChildren}
|
|
</AntdSchemaFieldAdaptor>
|
|
);
|
|
})`
|
|
display: flex;
|
|
.text-box-words:nth-child(1) {
|
|
margin-left: 0;
|
|
}
|
|
.text-box-words {
|
|
margin-bottom: 0 !important;
|
|
${isV4 ? 'line-height:32px' : ''}
|
|
}
|
|
.text-box-field {
|
|
display: inline-block;
|
|
.ant-form-item {
|
|
margin-bottom: 0 !important;
|
|
}
|
|
}
|
|
.next-form-item {
|
|
margin-bottom: 0 !important;
|
|
}
|
|
.preview-text {
|
|
text-align: center !important;
|
|
}
|
|
`,
|
|
);
|
|
|
|
export default FormTextBox;
|