tachybase_todo/packages/app/src/components/fields/form-text-box/index.tsx
2021-04-06 12:52:59 +08:00

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;