Merge pull request #26339 from ant-design/feature-merge-master

chore: Feature merge master
This commit is contained in:
二货机器人 2020-08-22 22:50:50 +08:00 committed by GitHub
commit 949f1f46e6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 3416 additions and 3647 deletions

View File

@ -212,11 +212,10 @@ timeline: true
- Table
- 🆕 Table 添加 `rowSelection.dirty` 以支持异步数据下保留 `key`。[#24718](https://github.com/ant-design/ant-design/pull/24718)
- 🆕 Table `onChange` 添加 `action` 参数用于标示操作类型。[#24697](https://github.com/ant-design/ant-design/pull/24697)
- 🐞 Table 支持 `rowSelection.checkStrictly` 来完全受控节点。[#24931](https://github.com/ant-design/ant-design/pull/24931)
- 🐞 Table 支持 `rowSelection.checkStrictly`,现在父子节点选择状态可以关联了。[#24931](https://github.com/ant-design/ant-design/pull/24931)
- 🐞 修复 Table `onSelectAll``changeRows` 参数不正确的问题。[#24931](https://github.com/ant-design/ant-design/pull/24931)
- 🐞 修复 Table 树形数据叶节点行的展开按钮仍能被点击的问题。[#24931](https://github.com/ant-design/ant-design/pull/24931)
- 🐞 修复 Table 展开图标隐藏时仍然有鼠标手型的问题。[#25170](https://github.com/ant-design/ant-design/pull/25170)
- 🐞 修复 Table 展开图标隐藏时仍然有鼠标手型的问题。[#25170](https://github.com/ant-design/ant-design/pull/25170)
- TimePicker
- 🐞 修复 TimePicker 面板 12 AM 显示为 0 AM 的问题。[#25174](https://github.com/ant-design/ant-design/pull/25174)
- 🐞 修复 TimePicker 在 use12Hours 时没有用 0 23 来禁用小时的问题。[#25174](https://github.com/ant-design/ant-design/pull/25174)

View File

@ -99,9 +99,9 @@ exports[`renders ./components/empty/demo/config-provider.md correctly 1`] = `
<div
class="config-provider"
>
<h3>
<h4>
Select
</h3>
</h4>
<div
class="ant-select ant-select-single ant-select-show-arrow"
style="width:200px"
@ -159,9 +159,9 @@ exports[`renders ./components/empty/demo/config-provider.md correctly 1`] = `
</span>
</span>
</div>
<h3>
<h4>
TreeSelect
</h3>
</h4>
<div
class="ant-select ant-tree-select ant-select-single ant-select-show-arrow"
style="width:200px"
@ -219,9 +219,9 @@ exports[`renders ./components/empty/demo/config-provider.md correctly 1`] = `
</span>
</span>
</div>
<h3>
<h4>
Cascader
</h3>
</h4>
<span
class="ant-cascader-picker ant-cascader-picker-show-search"
style="width:200px"
@ -259,9 +259,9 @@ exports[`renders ./components/empty/demo/config-provider.md correctly 1`] = `
</svg>
</span>
</span>
<h3>
<h4>
Transfer
</h3>
</h4>
<div
class="ant-transfer"
>
@ -532,9 +532,9 @@ exports[`renders ./components/empty/demo/config-provider.md correctly 1`] = `
</div>
</div>
</div>
<h3>
<h4>
Table
</h3>
</h4>
<div
class="ant-table-wrapper"
style="margin-top:8px"
@ -640,9 +640,9 @@ exports[`renders ./components/empty/demo/config-provider.md correctly 1`] = `
</div>
</div>
</div>
<h3>
<h4>
List
</h3>
</h4>
<div
class="ant-list ant-list-split"
>

View File

@ -58,19 +58,19 @@ class Demo extends React.Component {
<ConfigProvider renderEmpty={customize && customizeRenderEmpty}>
<div className="config-provider">
<h3>Select</h3>
<h4>Select</h4>
<Select style={style} />
<h3>TreeSelect</h3>
<h4>TreeSelect</h4>
<TreeSelect style={style} treeData={[]} />
<h3>Cascader</h3>
<h4>Cascader</h4>
<Cascader style={style} options={[]} showSearch />
<h3>Transfer</h3>
<h4>Transfer</h4>
<Transfer />
<h3>Table</h3>
<h4>Table</h4>
<Table
style={{ marginTop: 8 }}
columns={[
@ -87,7 +87,7 @@ class Demo extends React.Component {
]}
/>
<h3>List</h3>
<h4>List</h4>
<List />
</div>
</ConfigProvider>
@ -100,7 +100,7 @@ ReactDOM.render(<Demo />, mountNode);
```
<style>
.code-box-demo .config-provider h3 {
.code-box-demo .config-provider h4 {
font-size: inherit;
margin: 16px 0 8px 0;
}

View File

@ -29,7 +29,7 @@ class TextArea extends React.Component<TextAreaProps, TextAreaState> {
}
static getDerivedStateFromProps(nextProps: TextAreaProps) {
if ('value' in nextProps) {
if (nextProps.value !== undefined) {
return {
value: nextProps.value,
};
@ -38,7 +38,7 @@ class TextArea extends React.Component<TextAreaProps, TextAreaState> {
}
setValue(value: string, callback?: () => void) {
if (!('value' in this.props)) {
if (this.props.value === undefined) {
this.setState({ value }, callback);
}
}

View File

@ -242,4 +242,10 @@ describe('TextArea allowClear', () => {
expect(setSelectionRangeFn).toHaveBeenCalled();
wrapper.unmount();
});
// https://github.com/ant-design/ant-design/issues/26308
it('should display defaultValue when value is undefined', () => {
const wrapper = mount(<Input.TextArea defaultValue="Light" value={undefined} />);
expect(wrapper.find('textarea').at(0).getDOMNode().value).toBe('Light');
});
});

View File

@ -61,8 +61,9 @@ export function useLocaleReceiver<T extends LocaleComponent>(
const componentLocale = React.useMemo(() => {
const locale = defaultLocale || defaultLocaleData[componentName || 'global'];
const localeFromContext = componentName && antLocale ? antLocale[componentName] : {};
return {
...(typeof locale === 'function' ? locale() : locale),
...(typeof locale === 'function' ? (locale as Function)() : locale),
...(localeFromContext || {}),
};
}, [componentName, defaultLocale, antLocale]);

View File

@ -6,10 +6,20 @@ interface StepsProps extends ProgressProps {
steps: number;
size?: ProgressSize;
strokeColor?: string;
trailColor?: string;
}
const Steps: React.FC<StepsProps> = props => {
const { size, steps, percent = 0, strokeWidth = 8, strokeColor, prefixCls, children } = props;
const {
size,
steps,
percent = 0,
strokeWidth = 8,
strokeColor,
trailColor,
prefixCls,
children,
} = props;
const current = Math.floor(steps * (percent / 100));
const stepWidth = size === 'small' ? 2 : 14;
const styledSteps = [];
@ -21,7 +31,7 @@ const Steps: React.FC<StepsProps> = props => {
[`${prefixCls}-steps-item-active`]: i <= current - 1,
})}
style={{
backgroundColor: i <= current - 1 ? strokeColor : undefined,
backgroundColor: i <= current - 1 ? strokeColor : trailColor,
width: stepWidth,
height: strokeWidth,
}}

View File

@ -608,3 +608,9 @@ exports[`Progress should support steps 1`] = `
</div>
</div>
`;
exports[`Progress steps should have default percent 0 1`] = `
<div
class="undefined-steps-outer"
/>
`;

View File

@ -2,6 +2,7 @@ import React from 'react';
import { mount } from 'enzyme';
import Progress from '..';
import { handleGradient, sortGradient } from '../Line';
import ProgressSteps from '../Steps';
import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
@ -167,6 +168,18 @@ describe('Progress', () => {
);
});
it('steps should support trailColor', () => {
const wrapper = mount(<Progress steps={5} percent={20} trailColor="#1890ee" />);
expect(wrapper.find('.ant-progress-steps-item').at(1).getDOMNode().style.backgroundColor).toBe(
'rgb(24, 144, 238)',
);
});
it('steps should have default percent 0', () => {
const wrapper = mount(<ProgressSteps />);
expect(wrapper.render()).toMatchSnapshot();
});
it('should warnning if use `progress` in success', () => {
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
mount(<Progress percent={60} success={{ progress: 30 }} />);

View File

@ -55,8 +55,7 @@
@text-color-inverse: @white;
@icon-color: inherit;
@icon-color-hover: fade(@black, 75%);
@heading-color: fade(#000, 85%);
@heading-color-dark: fade(@white, 100%);
@heading-color: fade(@black, 85%);
@text-color-dark: fade(@white, 85%);
@text-color-secondary-dark: fade(@white, 65%);
@text-selection-bg: @primary-color;

View File

@ -114,6 +114,7 @@ class ListBody extends React.Component<TransferListBodyProps, TransferListBodySt
paginationNode = (
<Pagination
simple
size="small"
disabled={globalDisabled}
className={`${prefixCls}-pagination`}
total={filteredRenderItems.length}

View File

@ -61,38 +61,36 @@ exports[`renders ./components/transfer/demo/advanced.md correctly 1`] = `
<div
class="ant-transfer-list-body-search-wrapper"
>
<div>
<input
class="ant-input ant-transfer-list-search"
placeholder="Search here"
type="text"
value=""
/>
<input
class="ant-input ant-transfer-list-search"
placeholder="Search here"
type="text"
value=""
/>
<span
class="ant-transfer-list-search-action"
>
<span
class="ant-transfer-list-search-action"
aria-label="search"
class="anticon anticon-search"
role="img"
>
<span
aria-label="search"
class="anticon anticon-search"
role="img"
<svg
aria-hidden="true"
class=""
data-icon="search"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<svg
aria-hidden="true"
class=""
data-icon="search"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
/>
</svg>
</span>
<path
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
/>
</svg>
</span>
</div>
</span>
</div>
<div
class="ant-transfer-list-body-not-found"
@ -278,38 +276,36 @@ exports[`renders ./components/transfer/demo/advanced.md correctly 1`] = `
<div
class="ant-transfer-list-body-search-wrapper"
>
<div>
<input
class="ant-input ant-transfer-list-search"
placeholder="Search here"
type="text"
value=""
/>
<input
class="ant-input ant-transfer-list-search"
placeholder="Search here"
type="text"
value=""
/>
<span
class="ant-transfer-list-search-action"
>
<span
class="ant-transfer-list-search-action"
aria-label="search"
class="anticon anticon-search"
role="img"
>
<span
aria-label="search"
class="anticon anticon-search"
role="img"
<svg
aria-hidden="true"
class=""
data-icon="search"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<svg
aria-hidden="true"
class=""
data-icon="search"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
/>
</svg>
</span>
<path
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
/>
</svg>
</span>
</div>
</span>
</div>
<div
class="ant-transfer-list-body-not-found"
@ -383,6 +379,7 @@ exports[`renders ./components/transfer/demo/basic.md correctly 1`] = `
Array [
<div
class="ant-transfer"
style="margin-bottom:16px"
>
<div
class="ant-transfer-list"
@ -1070,30 +1067,21 @@ Array [
</div>
</div>
</div>,
<div
class="ant-space ant-space-horizontal ant-space-align-center"
style="margin-top:16px"
<button
aria-checked="false"
class="ant-switch"
role="switch"
type="button"
>
<div
class="ant-space-item"
class="ant-switch-handle"
/>
<span
class="ant-switch-inner"
>
<button
aria-checked="false"
class="ant-switch"
role="switch"
type="button"
>
<div
class="ant-switch-handle"
/>
<span
class="ant-switch-inner"
>
disabled
</span>
</button>
</div>
</div>,
disabled
</span>
</button>,
]
`;
@ -2068,6 +2056,7 @@ exports[`renders ./components/transfer/demo/oneWay.md correctly 1`] = `
Array [
<div
class="ant-transfer"
style="margin-bottom:16px"
>
<div
class="ant-transfer-list"
@ -2792,30 +2781,21 @@ Array [
</div>
</div>
</div>,
<div
class="ant-space ant-space-horizontal ant-space-align-center"
style="margin-top:16px"
<button
aria-checked="false"
class="ant-switch"
role="switch"
type="button"
>
<div
class="ant-space-item"
class="ant-switch-handle"
/>
<span
class="ant-switch-inner"
>
<button
aria-checked="false"
class="ant-switch"
role="switch"
type="button"
>
<div
class="ant-switch-handle"
/>
<span
class="ant-switch-inner"
>
disabled
</span>
</button>
</div>
</div>,
disabled
</span>
</button>,
]
`;
@ -2879,38 +2859,36 @@ exports[`renders ./components/transfer/demo/search.md correctly 1`] = `
<div
class="ant-transfer-list-body-search-wrapper"
>
<div>
<input
class="ant-input ant-transfer-list-search"
placeholder="Search here"
type="text"
value=""
/>
<input
class="ant-input ant-transfer-list-search"
placeholder="Search here"
type="text"
value=""
/>
<span
class="ant-transfer-list-search-action"
>
<span
class="ant-transfer-list-search-action"
aria-label="search"
class="anticon anticon-search"
role="img"
>
<span
aria-label="search"
class="anticon anticon-search"
role="img"
<svg
aria-hidden="true"
class=""
data-icon="search"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<svg
aria-hidden="true"
class=""
data-icon="search"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
/>
</svg>
</span>
<path
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
/>
</svg>
</span>
</div>
</span>
</div>
<div
class="ant-transfer-list-body-not-found"
@ -3076,38 +3054,36 @@ exports[`renders ./components/transfer/demo/search.md correctly 1`] = `
<div
class="ant-transfer-list-body-search-wrapper"
>
<div>
<input
class="ant-input ant-transfer-list-search"
placeholder="Search here"
type="text"
value=""
/>
<input
class="ant-input ant-transfer-list-search"
placeholder="Search here"
type="text"
value=""
/>
<span
class="ant-transfer-list-search-action"
>
<span
class="ant-transfer-list-search-action"
aria-label="search"
class="anticon anticon-search"
role="img"
>
<span
aria-label="search"
class="anticon anticon-search"
role="img"
<svg
aria-hidden="true"
class=""
data-icon="search"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<svg
aria-hidden="true"
class=""
data-icon="search"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
/>
</svg>
</span>
<path
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
/>
</svg>
</span>
</div>
</span>
</div>
<div
class="ant-transfer-list-body-not-found"

View File

@ -5,37 +5,15 @@ exports[`Transfer.Search should show cross icon when input value exists 1`] = `
placeholder=""
value=""
>
<div>
<Input
onChange={[Function]}
placeholder=""
type="text"
value=""
>
<ClearableLabeledInput
bordered={true}
element={
<input
className="ant-input"
onBlur={[Function]}
onChange={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
placeholder=""
type="text"
value=""
/>
}
focused={false}
handleReset={[Function]}
inputType="input"
onChange={[Function]}
placeholder=""
prefixCls="ant-input"
triggerFocus={[Function]}
type="text"
value=""
>
<Input
onChange={[Function]}
placeholder=""
type="text"
value=""
>
<ClearableLabeledInput
bordered={true}
element={
<input
className="ant-input"
onBlur={[Function]}
@ -46,86 +24,106 @@ exports[`Transfer.Search should show cross icon when input value exists 1`] = `
type="text"
value=""
/>
</ClearableLabeledInput>
</Input>
<span
className="undefined-action"
}
focused={false}
handleReset={[Function]}
inputType="input"
onChange={[Function]}
placeholder=""
prefixCls="ant-input"
triggerFocus={[Function]}
type="text"
value=""
>
<ForwardRef(SearchOutlined)>
<AntdIcon
icon={
Object {
"icon": Object {
"attrs": Object {
"focusable": "false",
"viewBox": "64 64 896 896",
},
"children": Array [
Object {
"attrs": Object {
"d": "M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z",
},
"tag": "path",
},
],
"tag": "svg",
<input
className="ant-input"
onBlur={[Function]}
onChange={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
placeholder=""
type="text"
value=""
/>
</ClearableLabeledInput>
</Input>
<span
className="undefined-action"
>
<ForwardRef(SearchOutlined)>
<AntdIcon
icon={
Object {
"icon": Object {
"attrs": Object {
"focusable": "false",
"viewBox": "64 64 896 896",
},
"name": "search",
"theme": "outlined",
}
}
>
<span
aria-label="search"
className="anticon anticon-search"
role="img"
>
<IconReact
className=""
icon={
"children": Array [
Object {
"icon": Object {
"attrs": Object {
"focusable": "false",
"viewBox": "64 64 896 896",
},
"children": Array [
Object {
"attrs": Object {
"d": "M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z",
},
"tag": "path",
},
],
"tag": "svg",
"attrs": Object {
"d": "M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z",
},
"name": "search",
"theme": "outlined",
}
"tag": "path",
},
],
"tag": "svg",
},
"name": "search",
"theme": "outlined",
}
}
>
<span
aria-label="search"
className="anticon anticon-search"
role="img"
>
<IconReact
className=""
icon={
Object {
"icon": Object {
"attrs": Object {
"focusable": "false",
"viewBox": "64 64 896 896",
},
"children": Array [
Object {
"attrs": Object {
"d": "M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z",
},
"tag": "path",
},
],
"tag": "svg",
},
"name": "search",
"theme": "outlined",
}
}
>
<svg
aria-hidden="true"
className=""
data-icon="search"
fill="currentColor"
focusable="false"
height="1em"
key="svg-search"
viewBox="64 64 896 896"
width="1em"
>
<svg
aria-hidden="true"
className=""
data-icon="search"
fill="currentColor"
focusable="false"
height="1em"
key="svg-search"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
key="svg-search-svg-0"
/>
</svg>
</IconReact>
</span>
</AntdIcon>
</ForwardRef(SearchOutlined)>
</span>
</div>
<path
d="M909.6 854.5L649.9 594.8C690.2 542.7 712 479 712 412c0-80.2-31.3-155.4-87.9-212.1-56.6-56.7-132-87.9-212.1-87.9s-155.5 31.3-212.1 87.9C143.2 256.5 112 331.8 112 412c0 80.1 31.3 155.5 87.9 212.1C256.5 680.8 331.8 712 412 712c67 0 130.6-21.8 182.7-62l259.7 259.6a8.2 8.2 0 0011.6 0l43.6-43.5a8.2 8.2 0 000-11.6zM570.4 570.4C528 612.7 471.8 636 412 636s-116-23.3-158.4-65.6C211.3 528 188 471.8 188 412s23.3-116.1 65.6-158.4C296 211.3 352.2 188 412 188s116.1 23.2 158.4 65.6S636 352.2 636 412s-23.3 116.1-65.6 158.4z"
key="svg-search-svg-0"
/>
</svg>
</IconReact>
</span>
</AntdIcon>
</ForwardRef(SearchOutlined)>
</span>
</Search>
`;
@ -134,37 +132,15 @@ exports[`Transfer.Search should show cross icon when input value exists 2`] = `
placeholder=""
value="a"
>
<div>
<Input
onChange={[Function]}
placeholder=""
type="text"
value="a"
>
<ClearableLabeledInput
bordered={true}
element={
<input
className="ant-input"
onBlur={[Function]}
onChange={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
placeholder=""
type="text"
value="a"
/>
}
focused={false}
handleReset={[Function]}
inputType="input"
onChange={[Function]}
placeholder=""
prefixCls="ant-input"
triggerFocus={[Function]}
type="text"
value="a"
>
<Input
onChange={[Function]}
placeholder=""
type="text"
value="a"
>
<ClearableLabeledInput
bordered={true}
element={
<input
className="ant-input"
onBlur={[Function]}
@ -175,87 +151,106 @@ exports[`Transfer.Search should show cross icon when input value exists 2`] = `
type="text"
value="a"
/>
</ClearableLabeledInput>
</Input>
<a
className="undefined-action"
href="#"
onClick={[Function]}
}
focused={false}
handleReset={[Function]}
inputType="input"
onChange={[Function]}
placeholder=""
prefixCls="ant-input"
triggerFocus={[Function]}
type="text"
value="a"
>
<ForwardRef(CloseCircleFilled)>
<AntdIcon
icon={
Object {
"icon": Object {
"attrs": Object {
"focusable": "false",
"viewBox": "64 64 896 896",
},
"children": Array [
Object {
"attrs": Object {
"d": "M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 01-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z",
},
"tag": "path",
},
],
"tag": "svg",
<input
className="ant-input"
onBlur={[Function]}
onChange={[Function]}
onFocus={[Function]}
onKeyDown={[Function]}
placeholder=""
type="text"
value="a"
/>
</ClearableLabeledInput>
</Input>
<a
className="undefined-action"
onClick={[Function]}
>
<ForwardRef(CloseCircleFilled)>
<AntdIcon
icon={
Object {
"icon": Object {
"attrs": Object {
"focusable": "false",
"viewBox": "64 64 896 896",
},
"name": "close-circle",
"theme": "filled",
}
}
>
<span
aria-label="close-circle"
className="anticon anticon-close-circle"
role="img"
>
<IconReact
className=""
icon={
"children": Array [
Object {
"icon": Object {
"attrs": Object {
"focusable": "false",
"viewBox": "64 64 896 896",
},
"children": Array [
Object {
"attrs": Object {
"d": "M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 01-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z",
},
"tag": "path",
},
],
"tag": "svg",
"attrs": Object {
"d": "M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 01-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z",
},
"name": "close-circle",
"theme": "filled",
}
"tag": "path",
},
],
"tag": "svg",
},
"name": "close-circle",
"theme": "filled",
}
}
>
<span
aria-label="close-circle"
className="anticon anticon-close-circle"
role="img"
>
<IconReact
className=""
icon={
Object {
"icon": Object {
"attrs": Object {
"focusable": "false",
"viewBox": "64 64 896 896",
},
"children": Array [
Object {
"attrs": Object {
"d": "M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 01-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z",
},
"tag": "path",
},
],
"tag": "svg",
},
"name": "close-circle",
"theme": "filled",
}
}
>
<svg
aria-hidden="true"
className=""
data-icon="close-circle"
fill="currentColor"
focusable="false"
height="1em"
key="svg-close-circle"
viewBox="64 64 896 896"
width="1em"
>
<svg
aria-hidden="true"
className=""
data-icon="close-circle"
fill="currentColor"
focusable="false"
height="1em"
key="svg-close-circle"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 01-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"
key="svg-close-circle-svg-0"
/>
</svg>
</IconReact>
</span>
</AntdIcon>
</ForwardRef(CloseCircleFilled)>
</a>
</div>
<path
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 01-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"
key="svg-close-circle-svg-0"
/>
</svg>
</IconReact>
</span>
</AntdIcon>
</ForwardRef(CloseCircleFilled)>
</a>
</Search>
`;

View File

@ -6,6 +6,24 @@ import Transfer from '../index';
describe('Transfer.Search', () => {
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
const dataSource = [
{
key: 'a',
title: 'a',
description: 'a',
},
{
key: 'b',
title: 'b',
description: 'b',
},
{
key: 'c',
title: 'c',
description: 'c',
},
];
afterEach(() => {
errorSpy.mockReset();
});
@ -16,33 +34,13 @@ describe('Transfer.Search', () => {
it('should show cross icon when input value exists', () => {
const wrapper = mount(<Search value="" />);
expect(wrapper).toMatchSnapshot();
wrapper.setProps({ value: 'a' });
expect(wrapper).toMatchSnapshot();
});
it('onSearch', () => {
jest.useFakeTimers();
const dataSource = [
{
key: 'a',
title: 'a',
description: 'a',
},
{
key: 'b',
title: 'b',
description: 'b',
},
{
key: 'c',
title: 'c',
description: 'c',
},
];
const onSearch = jest.fn();
const wrapper = mount(
@ -55,36 +53,40 @@ describe('Transfer.Search', () => {
showSearch
/>,
);
wrapper
.find('.ant-input')
.at(0)
.simulate('change', { target: { value: 'a' } });
expect(onSearch).toHaveBeenCalledWith('left', 'a');
onSearch.mockReset();
wrapper
.find('.ant-transfer-list-search-action')
.at(0)
.simulate('click');
wrapper.find('.ant-transfer-list-search-action').at(0).simulate('click');
expect(onSearch).toHaveBeenCalledWith('left', '');
jest.useRealTimers();
});
it('legacy props#onSearchChange doesnot work anymore', () => {
const onSearchChange = jest.fn();
const wrapper = mount(
<Transfer render={item => item.title} onSearchChange={onSearchChange} showSearch />,
);
wrapper
.find('.ant-input')
.at(0)
.simulate('change', { target: { value: 'a' } });
expect(errorSpy.mock.calls.length).toBe(0);
expect(onSearchChange).not.toHaveBeenCalled();
});
// https://github.com/ant-design/ant-design/issues/26208
it('typing space should trigger filterOption', () => {
const filterOption = jest.fn();
const wrapper = mount(
<Transfer filterOption={filterOption} dataSource={dataSource} showSearch />,
);
wrapper
.find('.ant-input')
.at(0)
.simulate('change', { target: { value: ' ' } });
expect(filterOption).toHaveBeenCalledTimes(dataSource.length);
});
});

View File

@ -14,7 +14,7 @@ title:
The most basic usage of `Transfer` involves providing the source data and target keys arrays, plus the rendering and some callback functions.
```jsx
import { Space, Transfer, Switch } from 'antd';
import { Transfer, Switch } from 'antd';
const mockData = [];
for (let i = 0; i < 20; i++) {
@ -73,15 +73,14 @@ class App extends React.Component {
onScroll={this.handleScroll}
render={item => item.title}
disabled={disabled}
style={{ marginBottom: 16 }}
/>
<Switch
unCheckedChildren="disabled"
checkedChildren="disabled"
checked={disabled}
onChange={this.handleDisable}
/>
<Space style={{ marginTop: 16 }}>
<Switch
unCheckedChildren="disabled"
checkedChildren="disabled"
checked={disabled}
onChange={this.handleDisable}
/>
</Space>
</>
);
}

View File

@ -14,7 +14,7 @@ title:
Use `oneWay` to makes Transfer to one way style.
```jsx
import { Space, Transfer, Switch } from 'antd';
import { Transfer, Switch } from 'antd';
const mockData = [];
for (let i = 0; i < 20; i++) {
@ -74,15 +74,14 @@ class App extends React.Component {
render={item => item.title}
disabled={disabled}
oneWay
style={{ marginBottom: 16 }}
/>
<Switch
unCheckedChildren="disabled"
checkedChildren="disabled"
checked={disabled}
onChange={this.handleDisable}
/>
<Space style={{ marginTop: 16 }}>
<Switch
unCheckedChildren="disabled"
checkedChildren="disabled"
checked={disabled}
onChange={this.handleDisable}
/>
</Space>
</>
);
}

View File

@ -14,20 +14,18 @@ title:
Customize render list with Tree component.
```jsx
import React, { useState } from 'react';
import { Transfer, Tree } from 'antd';
// Customize Table Transfer
const isChecked = (selectedKeys, eventKey) => {
return selectedKeys.indexOf(eventKey) !== -1;
};
const isChecked = (selectedKeys, eventKey) => selectedKeys.indexOf(eventKey) !== -1;
const generateTree = (treeNodes = [], checkedKeys = []) => {
return treeNodes.map(({ children, ...props }) => ({
const generateTree = (treeNodes = [], checkedKeys = []) =>
treeNodes.map(({ children, ...props }) => ({
...props,
disabled: checkedKeys.includes(props.key),
children: generateTree(children, checkedKeys),
}));
};
const TreeTransfer = ({ dataSource, targetKeys, ...restProps }) => {
const transferDataSource = [];
@ -86,32 +84,20 @@ const treeData = [
{ key: '0-2', title: '0-3' },
];
class App extends React.Component {
state = {
targetKeys: [],
const App = () => {
const [targetKeys, setTargetKeys] = useState([]);
const onChange = keys => {
setTargetKeys(keys);
};
onChange = targetKeys => {
console.log('Target Keys:', targetKeys);
this.setState({ targetKeys });
};
render() {
const { targetKeys } = this.state;
return (
<>
<TreeTransfer dataSource={treeData} targetKeys={targetKeys} onChange={this.onChange} />
</>
);
}
}
return <TreeTransfer dataSource={treeData} targetKeys={targetKeys} onChange={onChange} />;
};
ReactDOM.render(<App />, mountNode);
```
<style>
.tree-transfer .ant-transfer-list:first-child {
width: 50%;
flex: none;
width: 50%;
}
</style>

View File

@ -125,7 +125,7 @@ export default class TransferList extends React.PureComponent<
const { renderedText } = renderedItem;
// Filter skip
if (filterValue && filterValue.trim() && !this.matchFilter(renderedText, item)) {
if (filterValue && !this.matchFilter(renderedText, item)) {
return null;
}

View File

@ -37,7 +37,7 @@ export default class Search extends React.Component<TransferSearchProps, any> {
const { placeholder, value, prefixCls, disabled } = this.props;
const icon =
value && value.length > 0 ? (
<a href="#" className={`${prefixCls}-action`} onClick={this.handleClear}>
<a className={`${prefixCls}-action`} onClick={this.handleClear}>
<CloseCircleFilled />
</a>
) : (
@ -47,7 +47,7 @@ export default class Search extends React.Component<TransferSearchProps, any> {
);
return (
<div>
<>
<Input
placeholder={placeholder}
className={prefixCls}
@ -56,7 +56,7 @@ export default class Search extends React.Component<TransferSearchProps, any> {
disabled={disabled}
/>
{icon}
</div>
</>
);
}
}

View File

@ -193,9 +193,9 @@
}
&-pagination {
flex: none;
align-self: flex-end;
padding: @padding-xs 0;
text-align: right;
border-top: @border-width-base @border-style-base @border-color-split;
}
&-body-not-found {

View File

@ -58,6 +58,11 @@ const LinksList = () => (
<li>
<a href="http://vue.ant.design" target="_blank">Ant Design of Vue</a>
</li>
<li>
<a href="https://ant-design-blazor.github.io/" target="_blank">
Ant Design Blazor
</a>
</li>
<li>
<a href="https://ecomfe.github.io/santd" target="_blank">
San UI Toolkit for Ant Design
@ -68,15 +73,6 @@ const LinksList = () => (
antizer (ClojureScript)
</a>
</li>
<li>
<a href="https://ant-design-blazor.github.io/" target="_blank">
ant-design-blazor/ant-design-blazor
</a>
<span class="ant-divider ant-divider-vertical" />
<a href="https://append-it.github.io/ant-design-blazor/" target="_blank">
append-it/ant-design-blazor
</a>
</li>
</ul>
);

View File

@ -58,6 +58,11 @@ const LinksList = () => (
<li>
<a href="http://vue.ant.design" target="_blank">Ant Design of Vue</a>
</li>
<li>
<a href="https://ant-design-blazor.github.io/" target="_blank">
Ant Design Blazor
</a>
</li>
<li>
<a href="https://ecomfe.github.io/santd" target="_blank">
San UI Toolkit for Ant Design
@ -68,15 +73,6 @@ const LinksList = () => (
antizer (ClojureScript)
</a>
</li>
<li>
<a href="https://ant-design-blazor.github.io/" target="_blank">
ant-design-blazor/ant-design-blazor
</a>
<span class="ant-divider ant-divider-vertical" />
<a href="https://append-it.github.io/ant-design-blazor/" target="_blank">
append-it/ant-design-blazor
</a>
</li>
</ul>
);

View File

@ -236,7 +236,7 @@
"preact": "^10.0.0",
"preact-compat": "^3.18.5",
"prettier": "^2.0.1",
"pretty-quick": "^2.0.0",
"pretty-quick": "^3.0.0",
"querystring": "^0.2.0",
"rc-footer": "^0.6.3",
"rc-queue-anim": "^1.6.12",
@ -278,7 +278,7 @@
"stylelint-declaration-block-no-ignored-properties": "^2.1.0",
"stylelint-order": "^4.0.0",
"theme-switcher": "^1.0.2",
"typescript": "~3.9.2",
"typescript": "~4.0.0",
"webpack-bundle-analyzer": "^3.6.0",
"xhr-mock": "^2.4.1",
"xhr2": "^0.2.0",

View File

@ -93,6 +93,15 @@
}
}
h1,
h2,
h3,
h4,
h5,
h6 {
color: @heading-color;
}
.markdown {
code,
pre,

View File

@ -17,6 +17,24 @@ const SourceImages = {
};
const MORE_LIST: MoreProps[] = [
{
title: '智能组件探索:这个工具栏会自动布局',
description:
'工程师只需要选择「我要展示哪些元素、每个元素有多少」,而「这些元素怎么摆」、「间距是多少」等细节问题都会根据规则自动生成。',
img: 'https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*A_F0SL5shbEAAAAAAAAAAAAAARQnAQ',
date: '2020-08-19',
source: 'zhihu',
href: 'https://zhuanlan.zhihu.com/p/188693322',
},
{
title: '一个好用的智能栅格工具是如何诞生的?',
description:
'和大家分享一下整个智能栅格的设计开发过程,并从中感受到设计的「穿透力」,聊聊如何打破界限、从表面到内核、从表象到本质。',
img: 'https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*hk19TqWVSDsAAAAAAAAAAAAAARQnAQ',
date: '2020-08-09',
source: 'zhihu',
href: 'https://zhuanlan.zhihu.com/p/176534657',
},
{
title: '设计考古:工具类产品 Office',
description:
@ -26,24 +44,6 @@ const MORE_LIST: MoreProps[] = [
source: 'zhihu',
href: 'https://zhuanlan.zhihu.com/p/90304083',
},
{
title: '数据可视化的驱动与使能',
description:
'“指哪打哪”形容听从驱使。在数据可视化设计中,操作“听从驱使”的可视化作品又是一种什么样的体验呢?',
img: 'https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*kGFrS4JCGo8AAAAAAAAAAABkARQnAQ',
date: '2019-10-30',
source: 'zhihu',
href: 'https://zhuanlan.zhihu.com/p/89352118',
},
{
title: '【AntV 关系图编辑器】交互设计沉思录',
description:
'AntV 是 Ant Design 设计语言中的可视化部分。本文讲述的是关系型数据 G6 中流程图编辑器的搭建经验。',
img: 'https://gw.alipayobjects.com/mdn/rms_08e378/afts/img/A*1fTSTKxbOqAAAAAAAAAAAABkARQnAQ',
date: '2019-09-11',
source: 'zhihu',
href: 'https://zhuanlan.zhihu.com/p/82146871',
},
{
title: '设计法则「映射」: 让你的设计更符合直觉',
description: