feat: support icon only in segmented (#35256)

* feat: support icon only with segmented

* fix: lint issue

* chore: update

* test: fix

* test: update snapshot
This commit is contained in:
vagusX 2022-04-28 19:39:52 +08:00 committed by GitHub
parent 5a6b3ccd98
commit eee3b50727
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 325 additions and 19 deletions

View File

@ -644,6 +644,84 @@ Array [
]
`;
exports[`renders ./components/segmented/demo/icon-only.md extend context correctly 1`] = `
<div
class="ant-segmented"
>
<label
class="ant-segmented-item ant-segmented-item-selected"
>
<input
checked=""
class="ant-segmented-item-input"
type="radio"
/>
<div
class="ant-segmented-item-label"
>
<span
class="ant-segmented-item-icon"
>
<span
aria-label="bars"
class="anticon anticon-bars"
role="img"
>
<svg
aria-hidden="true"
data-icon="bars"
fill="currentColor"
focusable="false"
height="1em"
viewBox="0 0 1024 1024"
width="1em"
>
<path
d="M912 192H328c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h584c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 284H328c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h584c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 284H328c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h584c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM104 228a56 56 0 10112 0 56 56 0 10-112 0zm0 284a56 56 0 10112 0 56 56 0 10-112 0zm0 284a56 56 0 10112 0 56 56 0 10-112 0z"
/>
</svg>
</span>
</span>
</div>
</label>
<label
class="ant-segmented-item"
>
<input
class="ant-segmented-item-input"
type="radio"
/>
<div
class="ant-segmented-item-label"
>
<span
class="ant-segmented-item-icon"
>
<span
aria-label="appstore"
class="anticon anticon-appstore"
role="img"
>
<svg
aria-hidden="true"
data-icon="appstore"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M464 144H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H212V212h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H612V212h200v200zM464 544H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H212V612h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H612V612h200v200z"
/>
</svg>
</span>
</span>
</div>
</label>
</div>
`;
exports[`renders ./components/segmented/demo/size.md extend context correctly 1`] = `
Array [
<div

View File

@ -644,6 +644,84 @@ Array [
]
`;
exports[`renders ./components/segmented/demo/icon-only.md correctly 1`] = `
<div
class="ant-segmented"
>
<label
class="ant-segmented-item ant-segmented-item-selected"
>
<input
checked=""
class="ant-segmented-item-input"
type="radio"
/>
<div
class="ant-segmented-item-label"
>
<span
class="ant-segmented-item-icon"
>
<span
aria-label="bars"
class="anticon anticon-bars"
role="img"
>
<svg
aria-hidden="true"
data-icon="bars"
fill="currentColor"
focusable="false"
height="1em"
viewBox="0 0 1024 1024"
width="1em"
>
<path
d="M912 192H328c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h584c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 284H328c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h584c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 284H328c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h584c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM104 228a56 56 0 10112 0 56 56 0 10-112 0zm0 284a56 56 0 10112 0 56 56 0 10-112 0zm0 284a56 56 0 10112 0 56 56 0 10-112 0z"
/>
</svg>
</span>
</span>
</div>
</label>
<label
class="ant-segmented-item"
>
<input
class="ant-segmented-item-input"
type="radio"
/>
<div
class="ant-segmented-item-label"
>
<span
class="ant-segmented-item-icon"
>
<span
aria-label="appstore"
class="anticon anticon-appstore"
role="img"
>
<svg
aria-hidden="true"
data-icon="appstore"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M464 144H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H212V212h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H612V212h200v200zM464 544H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H212V612h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H612V612h200v200z"
/>
</svg>
</span>
</span>
</div>
</label>
</div>
`;
exports[`renders ./components/segmented/demo/size.md correctly 1`] = `
Array [
<div

View File

@ -631,6 +631,87 @@ exports[`Segmented render segmented: disabled 1`] = `
</div>
`;
exports[`Segmented render with icons 1`] = `
<div
class="ant-segmented"
>
<label
class="ant-segmented-item ant-segmented-item-selected"
>
<input
checked=""
class="ant-segmented-item-input"
type="radio"
/>
<div
class="ant-segmented-item-label"
>
<span
class="ant-segmented-item-icon"
>
<span
aria-label="bars"
class="anticon anticon-bars"
role="img"
>
<svg
aria-hidden="true"
data-icon="bars"
fill="currentColor"
focusable="false"
height="1em"
viewBox="0 0 1024 1024"
width="1em"
>
<path
d="M912 192H328c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h584c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 284H328c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h584c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 284H328c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h584c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM104 228a56 56 0 10112 0 56 56 0 10-112 0zm0 284a56 56 0 10112 0 56 56 0 10-112 0zm0 284a56 56 0 10112 0 56 56 0 10-112 0z"
/>
</svg>
</span>
</span>
</div>
</label>
<label
class="ant-segmented-item"
>
<input
class="ant-segmented-item-input"
type="radio"
/>
<div
class="ant-segmented-item-label"
>
<span
class="ant-segmented-item-icon"
>
<span
aria-label="appstore"
class="anticon anticon-appstore"
role="img"
>
<svg
aria-hidden="true"
data-icon="appstore"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M464 144H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H212V212h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H612V212h200v200zM464 544H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H212V612h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H612V612h200v200z"
/>
</svg>
</span>
</span>
<span>
KanbanYes
</span>
</div>
</label>
</div>
`;
exports[`Segmented rtl render component should be rendered correctly in RTL direction 1`] = `
<div
class="ant-segmented ant-segmented-rtl"

View File

@ -1,5 +1,7 @@
import React from 'react';
import { mount } from 'enzyme';
import { AppstoreOutlined, BarsOutlined } from '@ant-design/icons';
import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
import Segmented from '../index';
@ -86,10 +88,7 @@ describe('Segmented', () => {
it('render segmented with string options', () => {
const handleValueChange = jest.fn();
const wrapper = mount(
<Segmented
options={['Daily', 'Weekly', 'Monthly']}
onChange={handleValueChange}
/>,
<Segmented options={['Daily', 'Weekly', 'Monthly']} onChange={handleValueChange} />,
);
expect(wrapper.render()).toMatchSnapshot();
@ -356,4 +355,25 @@ describe('Segmented', () => {
expect(wrapper.find(`.${prefixCls}`).at(0).hasClass(`${prefixCls}-lg`)).toBeTruthy();
});
it('render with icons', () => {
const wrapper = mount(
<Segmented
options={[
{
value: 'List',
icon: <BarsOutlined />,
},
{
value: 'Kanban',
label: 'KanbanYes',
icon: <AppstoreOutlined />,
},
]}
/>,
);
expect(wrapper.render()).toMatchSnapshot();
expect(wrapper.find(`span.${prefixCls}-item-icon`).length).toBe(2);
expect(wrapper.find(`div.${prefixCls}-item-label`).at(1).contains('KanbanYes')).toBeTruthy();
});
});

View File

@ -1,5 +1,5 @@
---
order: 10
order: 1
title:
zh-CN: Block 分段选择器
en-US: Block Segmented

View File

@ -1,5 +1,5 @@
---
order: 0
order: 3
title:
zh-CN: 受控模式
en-US: Controlled mode

View File

@ -1,5 +1,5 @@
---
order: 1
order: 4
title:
zh-CN: 自定义渲染
en-US: Custom Render

View File

@ -1,5 +1,5 @@
---
order: 0
order: 2
title:
zh-CN: 不可用
en-US: Basic

View File

@ -1,5 +1,5 @@
---
order: 0
order: 5
title:
zh-CN: 动态数据
en-US: Dynamic

View File

@ -0,0 +1,34 @@
---
order: 8
title:
zh-CN: 只设置图标
en-US: With Icon only
---
## zh-CN
在 Segmented Item 选项中只设置 Icon。
## en-US
Set `icon` without `label` for Segmented Item.
```jsx
import { Segmented } from 'antd';
import { AppstoreOutlined, BarsOutlined } from '@ant-design/icons';
export default () => (
<Segmented
options={[
{
value: 'List',
icon: <BarsOutlined />,
},
{
value: 'Kanban',
icon: <AppstoreOutlined />,
},
]}
/>
);
```

View File

@ -1,5 +1,5 @@
---
order: 1
order: 6
title:
zh-CN: 三种大小
en-US: Three sizes of Segmented

View File

@ -1,5 +1,5 @@
---
order: 0
order: 7
title:
zh-CN: 设置图标
en-US: With Icon

View File

@ -12,12 +12,27 @@ import SizeContext, { SizeType } from '../config-provider/SizeContext';
export type { SegmentedValue } from 'rc-segmented';
export interface SegmentedLabeledOption extends RcSegmentedLabeledOption {
/** Set icon for Segmented item */
icon?: React.ReactNode;
interface SegmentedLabeledOptionWithoutIcon extends RcSegmentedLabeledOption {
label: RcSegmentedLabeledOption['label'];
}
export interface SegmentedProps extends Omit<RCSegmentedProps, 'size'> {
interface SegmentedLabeledOptionWithIcon extends Omit<RcSegmentedLabeledOption, 'label'> {
label?: RcSegmentedLabeledOption['label'];
/** Set icon for Segmented item */
icon: React.ReactNode;
}
function isSegmentedLabeledOptionWithIcon(
option: SegmentedRawOption | SegmentedLabeledOptionWithIcon | SegmentedLabeledOptionWithoutIcon,
): option is SegmentedLabeledOptionWithIcon {
return typeof option === 'object' && !!(option as SegmentedLabeledOptionWithIcon)?.icon;
}
export type SegmentedLabeledOption =
| SegmentedLabeledOptionWithIcon
| SegmentedLabeledOptionWithoutIcon;
export interface SegmentedProps extends Omit<RCSegmentedProps, 'size' | 'options'> {
options: (SegmentedRawOption | SegmentedLabeledOption)[];
/** Option to fit width to its parent's width */
block?: boolean;
@ -46,14 +61,14 @@ const Segmented = React.forwardRef<HTMLDivElement, SegmentedProps>((props, ref)
const extendedOptions = React.useMemo(
() =>
options.map(option => {
if (typeof option === 'object' && option?.icon) {
if (isSegmentedLabeledOptionWithIcon(option)) {
const { icon, label, ...restOption } = option;
return {
...restOption,
label: (
<>
<span className={`${prefixCls}-item-icon`}>{icon}</span>
<span>{label}</span>
{label && <span>{label}</span>}
</>
),
};

View File

@ -61,8 +61,8 @@
}
// syntactic sugar to add `icon` for Segmented Item
&-icon {
margin-right: 6px;
&-icon + * {
margin-left: 6px;
}
&-input {