Skip to content

Commit

Permalink
feat(Form): support preferMarginToDisplayHelp, close #4641 (#4645)
Browse files Browse the repository at this point in the history
* feat(Form): support preferMarginToDisplayHelp to control help reverse offset, close #4641

* fix(Form): toggle token at different size

* chore(Form): lint tsdoc for preferMarginToDisplayHelp
  • Loading branch information
YSMJ1994 authored Dec 13, 2023
1 parent 54198f9 commit 5e7d9d3
Show file tree
Hide file tree
Showing 7 changed files with 125 additions and 38 deletions.
17 changes: 14 additions & 3 deletions src/form/error.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@ class Error extends React.Component {
*/
children: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
prefix: PropTypes.string,
preferMarginToDisplayHelp: PropTypes.bool,
};

static defaultProps = {
prefix: 'next-',
preferMarginToDisplayHelp: false,
};

static contextTypes = {
Expand All @@ -42,13 +44,22 @@ class Error extends React.Component {
};

render() {
const { children, name, prefix, style, className, field: _field, ...others } = this.props;
const {
children,
name,
prefix,
style,
className,
field: _field,
preferMarginToDisplayHelp,
...others
} = this.props;

if (children && typeof children !== 'function') {
return (
<div className={`${prefix}form-item-help`}>
{children}
<div className={`${prefix}form-item-help-margin-offset`} />
{!!preferMarginToDisplayHelp && <div className={`${prefix}form-item-help-margin-offset`} />}
</div>
);
}
Expand Down Expand Up @@ -92,7 +103,7 @@ class Error extends React.Component {
return (
<div {...others} className={cls} style={style}>
{result}
<div className={`${prefix}form-item-help-margin-offset`} />
{!!preferMarginToDisplayHelp && <div className={`${prefix}form-item-help-margin-offset`} />}
</div>
);
}
Expand Down
9 changes: 9 additions & 0 deletions src/form/form.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,12 @@ export default class Form extends React.Component {
* @version 1.20
*/
useLabelForErrorMessage: PropTypes.bool,
/**
* 倾向使用 item 的 margin 空间来展示 help
* @default false
* @version 1.26.37
*/
preferMarginToDisplayHelp: PropTypes.bool,
/**
* 表示是否显示 label 后面的冒号
* @version 1.22
Expand All @@ -166,6 +172,7 @@ export default class Form extends React.Component {
device: 'desktop',
colon: false,
disabled: false,
preferMarginToDisplayHelp: false,
};

static childContextTypes = {
Expand All @@ -175,6 +182,7 @@ export default class Form extends React.Component {
_formPreview: PropTypes.bool,
_formFullWidth: PropTypes.bool,
_formLabelForErrorMessage: PropTypes.bool,
_formMarginToDisplayHelp: PropTypes.bool,
};

constructor(props) {
Expand Down Expand Up @@ -216,6 +224,7 @@ export default class Form extends React.Component {
_formPreview: this.props.isPreview,
_formFullWidth: this.props.fullWidth,
_formLabelForErrorMessage: this.props.useLabelForErrorMessage,
_formMarginToDisplayHelp: this.props.preferMarginToDisplayHelp,
};
}

Expand Down
20 changes: 17 additions & 3 deletions src/form/item.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,12 @@ export default class Item extends React.Component {
* 是否使用 label 替换校验信息的 name 字段
*/
useLabelForErrorMessage: PropTypes.bool,
/**
* 倾向使用 item 的 margin 空间来展示 help
* @default false
* @version 1.26.37
*/
preferMarginToDisplayHelp: PropTypes.bool,
/**
* 表示是否显示 label 后面的冒号
*/
Expand Down Expand Up @@ -240,6 +246,7 @@ export default class Item extends React.Component {
_formPreview: PropTypes.bool,
_formFullWidth: PropTypes.bool,
_formLabelForErrorMessage: PropTypes.bool,
_formMarginToDisplayHelp: PropTypes.bool,
};

static _typeMark = 'form_item';
Expand Down Expand Up @@ -268,11 +275,18 @@ export default class Item extends React.Component {
}

getHelper(children) {
const help = this.props.help;
const _formField = this.context._formField;
const { help, preferMarginToDisplayHelp } = this.props;
const { _formField, _formMarginToDisplayHelp } = this.context;

const useMargin =
typeof preferMarginToDisplayHelp !== 'undefined' ? preferMarginToDisplayHelp : _formMarginToDisplayHelp;

return (
<Error name={help === undefined ? this.getNames(children) : undefined} field={_formField}>
<Error
name={help === undefined ? this.getNames(children) : undefined}
field={_formField}
preferMarginToDisplayHelp={useMargin}
>
{help}
</Error>
);
Expand Down
12 changes: 12 additions & 0 deletions src/form/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@

#{$form-prefix}-item {
margin-bottom: 0;

.#{$css-prefix}form-item-help-margin-offset {
margin-top: 0;
}
}

#{$form-prefix}-item.#{$css-prefix}left {
Expand Down Expand Up @@ -151,6 +155,10 @@
#{$form-prefix}-item-label {
font-size: $form-element-large-font-size;
}

.#{$css-prefix}form-item-help-margin-offset {
margin-top: -$form-item-l-margin-b;
}
}
&.#{$css-prefix}small {
margin-bottom: $form-item-s-margin-b;
Expand All @@ -165,6 +173,10 @@
#{$form-prefix}-item-label {
font-size: $form-element-small-font-size;
}

.#{$css-prefix}form-item-help-margin-offset {
margin-top: -$form-item-s-margin-b;
}
}
&.#{$css-prefix}top > #{$form-prefix}-item-label {
margin-bottom: $form-top-label-margin-b;
Expand Down
89 changes: 57 additions & 32 deletions test/form/validate-spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React from 'react';
import ReactDOM from 'react-dom';
import ReactTestUtils from 'react-dom/test-utils';
import Enzyme, { mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
Expand All @@ -8,10 +7,13 @@ import Input from '../../src/input';
import Form from '../../src/form/index';
import Field from '../../src/field';
import { dom } from '../../src/util';
import testUtil from '../util/index';

const FormItem = Form.Item;
const Submit = Form.Submit;
const Reset = Form.Reset;
const { getStyle } = dom;
const { render } = testUtil;
Enzyme.configure({ adapter: new Adapter() });

describe('Submit', () => {
Expand Down Expand Up @@ -445,46 +447,69 @@ describe('Reset', () => {
});

describe('Error', () => {
let mountNode;

const getVerDistance = (node1, node2) => {
const rect1 = node1.getBoundingClientRect();
const rect2 = node2.getBoundingClientRect();
return rect2.top - rect1.top - rect1.height;
};

beforeEach(() => {
mountNode = document.createElement('div');
document.body.appendChild(mountNode);
});
describe('preferMarginToDisplayHelp', () => {
const getDistance = wrapper => {
const items = wrapper.find('.next-form-item');
assert(items.length === 3);
return getVerDistance(items[0].querySelector('.next-input'), items[1]);
};
function Demo({ formUseMargin, itemUseMargin }) {
return (
<Form preferMarginToDisplayHelp={formUseMargin}>
<FormItem label="item1" required preferMarginToDisplayHelp={itemUseMargin}>
<Input name="name" />
</FormItem>
<FormItem label="item2">
<Input name="name2" />
</FormItem>
<FormItem>
<Form.Submit validate>submit</Form.Submit>
</FormItem>
</Form>
);
}
it('form should support preferMarginToDisplayHelp', () => {
const wrapper = render(<Demo />);

afterEach(() => {
ReactDOM.unmountComponentAtNode(mountNode);
document.body.removeChild(mountNode);
});
ReactTestUtils.Simulate.click(wrapper.find('.next-btn')[0]);
const oldDistance = getDistance(wrapper);

it('the error does not affect the style', () => {
ReactDOM.render(
<Form>
<FormItem label="item1" required>
<Input />
</FormItem>
<FormItem label="item2">
<Input />
</FormItem>
<FormItem>
<Form.Submit>submit</Form.Submit>
</FormItem>
</Form>,
mountNode
);
wrapper.setProps({ formUseMargin: true });
const newDistance = getDistance(wrapper);

assert(newDistance < oldDistance);

wrapper.unmount();
});
it('form item should support preferMarginToDisplayHelp', () => {
const wrapper = render(<Demo />);
ReactTestUtils.Simulate.click(wrapper.find('.next-btn')[0]);
const oldDistance = getDistance(wrapper);

wrapper.setProps({ itemUseMargin: true });
const newDistance = getDistance(wrapper);

assert(newDistance < oldDistance);

wrapper.unmount();
});
it('form item > form when cross preferMarginToDisplayHelp at same time', () => {
const wrapper = render(<Demo />);
ReactTestUtils.Simulate.click(wrapper.find('.next-btn')[0]);
const oldDistance = getDistance(wrapper);

wrapper.setProps({ formUseMargin: false, itemUseMargin: true });
const newDistance = getDistance(wrapper);

const items = mountNode.querySelectorAll('.next-form-item');
assert(items.length === 3);
assert(newDistance < oldDistance);

const oldDistance = getVerDistance(items[0], items[1]);
ReactTestUtils.Simulate.click(mountNode.querySelector('.next-btn'));
const newDistance = getVerDistance(items[0], items[1]);
assert(oldDistance === newDistance);
wrapper.unmount();
});
});
});
3 changes: 3 additions & 0 deletions test/util/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import React from 'react';
import ReactDOM from 'react-dom';

const delay = time => new Promise(resolve => setTimeout(resolve, time));

const render = element => {
Expand Down
13 changes: 13 additions & 0 deletions types/form/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,13 @@ export interface ItemProps extends React.HTMLAttributes<HTMLElement>, CommonProp
*/
useLabelForErrorMessage?: boolean;

/**
* 倾向使用 item 的 margin 空间来展示 help
* @default false
* @version 1.26.37
*/
preferMarginToDisplayHelp?: boolean;

/**
* 表示是否显示 label 后面的冒号
*/
Expand Down Expand Up @@ -530,6 +537,12 @@ export interface FormProps extends HTMLAttributesWeak, CommonProps {
* 是否使用 label 替换校验信息的 name 字段
*/
useLabelForErrorMessage?: boolean;
/**
* 倾向使用 item 的 margin 空间来展示 help
* @default false
* @version 1.26.37
*/
preferMarginToDisplayHelp?: boolean;
}

export default class Form extends React.Component<FormProps, any> {
Expand Down

0 comments on commit 5e7d9d3

Please sign in to comment.