mirror of
https://github.com/zhigang1992/react.git
synced 2026-02-10 09:03:57 +08:00
Merge pull request #158 from unix/badge
feat(badge): supoort to anchor with other components
This commit is contained in:
124
components/badge/__tests__/__snapshots__/anchor.test.tsx.snap
Normal file
124
components/badge/__tests__/__snapshots__/anchor.test.tsx.snap
Normal file
@@ -0,0 +1,124 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`BadgeAnchor should be support multiple position 1`] = `
|
||||
"<div class=\\"anchor\\"><button>btn</button><sup><span class=\\" \\">test<style>
|
||||
span {
|
||||
display: inline-block;
|
||||
padding: 4px 7px;
|
||||
border-radius: 16px;
|
||||
font-variant: tabular-nums;
|
||||
line-height: 1;
|
||||
vertical-align: middle;
|
||||
background-color: #000;
|
||||
color: #fff;
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
</style></span></sup><style>
|
||||
.anchor {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
vertical-align: middle;
|
||||
flex-shrink: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
sup {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: auto;
|
||||
right: 0;
|
||||
bottom: auto;
|
||||
transform: translate(50%, -50%);
|
||||
transform-origin: 100% 0%;
|
||||
z-index: 1;
|
||||
}
|
||||
</style></div>"
|
||||
`;
|
||||
|
||||
exports[`BadgeAnchor should be support multiple position 2`] = `
|
||||
"<div class=\\"anchor\\"><button>btn</button><sup><span class=\\" \\">test<style>
|
||||
span {
|
||||
display: inline-block;
|
||||
padding: 4px 7px;
|
||||
border-radius: 16px;
|
||||
font-variant: tabular-nums;
|
||||
line-height: 1;
|
||||
vertical-align: middle;
|
||||
background-color: #000;
|
||||
color: #fff;
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
</style></span></sup><style>
|
||||
.anchor {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
vertical-align: middle;
|
||||
flex-shrink: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
sup {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: auto;
|
||||
bottom: auto;
|
||||
transform: translate(-50%, -50%);
|
||||
transform-origin: 0% 0%;
|
||||
z-index: 1;
|
||||
}
|
||||
</style></div>"
|
||||
`;
|
||||
|
||||
exports[`BadgeAnchor should be support multiple position 3`] = `
|
||||
"<div class=\\"anchor\\"><button>btn</button><sup><span class=\\" \\">test<style>
|
||||
span {
|
||||
display: inline-block;
|
||||
padding: 4px 7px;
|
||||
border-radius: 16px;
|
||||
font-variant: tabular-nums;
|
||||
line-height: 1;
|
||||
vertical-align: middle;
|
||||
background-color: #000;
|
||||
color: #fff;
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
</style></span></sup><style>
|
||||
.anchor {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
vertical-align: middle;
|
||||
flex-shrink: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
sup {
|
||||
position: absolute;
|
||||
top: auto;
|
||||
left: auto;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
transform: translate(50%, 50%);
|
||||
transform-origin: 100% 100%;
|
||||
z-index: 1;
|
||||
}
|
||||
</style></div>"
|
||||
`;
|
||||
@@ -11,7 +11,7 @@ initialize {
|
||||
"children": Array [
|
||||
Object {
|
||||
"attribs": Object {
|
||||
"class": "",
|
||||
"class": " ",
|
||||
},
|
||||
"children": Array [
|
||||
Object {
|
||||
@@ -33,6 +33,11 @@ initialize {
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
"parent": [Circular],
|
||||
@@ -70,6 +75,11 @@ initialize {
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
"parent": [Circular],
|
||||
@@ -97,7 +107,7 @@ initialize {
|
||||
"namespace": "http://www.w3.org/1999/xhtml",
|
||||
"next": Object {
|
||||
"attribs": Object {
|
||||
"class": "",
|
||||
"class": " ",
|
||||
},
|
||||
"children": Array [
|
||||
Object {
|
||||
@@ -119,6 +129,11 @@ initialize {
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
"parent": [Circular],
|
||||
@@ -156,6 +171,11 @@ initialize {
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
"parent": [Circular],
|
||||
@@ -183,7 +203,7 @@ initialize {
|
||||
"namespace": "http://www.w3.org/1999/xhtml",
|
||||
"next": Object {
|
||||
"attribs": Object {
|
||||
"class": "",
|
||||
"class": " ",
|
||||
},
|
||||
"children": Array [
|
||||
Object {
|
||||
@@ -205,6 +225,11 @@ initialize {
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
"parent": [Circular],
|
||||
@@ -242,6 +267,11 @@ initialize {
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
"parent": [Circular],
|
||||
@@ -269,7 +299,7 @@ initialize {
|
||||
"namespace": "http://www.w3.org/1999/xhtml",
|
||||
"next": Object {
|
||||
"attribs": Object {
|
||||
"class": "",
|
||||
"class": " ",
|
||||
},
|
||||
"children": Array [
|
||||
Object {
|
||||
@@ -291,6 +321,11 @@ initialize {
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
"parent": [Circular],
|
||||
@@ -328,6 +363,11 @@ initialize {
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
"parent": [Circular],
|
||||
@@ -396,7 +436,7 @@ initialize {
|
||||
},
|
||||
Object {
|
||||
"attribs": Object {
|
||||
"class": "",
|
||||
"class": " ",
|
||||
},
|
||||
"children": Array [
|
||||
Object {
|
||||
@@ -418,6 +458,11 @@ initialize {
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
"parent": [Circular],
|
||||
@@ -455,6 +500,11 @@ initialize {
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
"parent": [Circular],
|
||||
@@ -482,7 +532,7 @@ initialize {
|
||||
"namespace": "http://www.w3.org/1999/xhtml",
|
||||
"next": Object {
|
||||
"attribs": Object {
|
||||
"class": "",
|
||||
"class": " ",
|
||||
},
|
||||
"children": Array [
|
||||
Object {
|
||||
@@ -504,6 +554,11 @@ initialize {
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
"parent": [Circular],
|
||||
@@ -541,6 +596,11 @@ initialize {
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
"parent": [Circular],
|
||||
@@ -568,7 +628,7 @@ initialize {
|
||||
"namespace": "http://www.w3.org/1999/xhtml",
|
||||
"next": Object {
|
||||
"attribs": Object {
|
||||
"class": "",
|
||||
"class": " ",
|
||||
},
|
||||
"children": Array [
|
||||
Object {
|
||||
@@ -590,6 +650,11 @@ initialize {
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
"parent": [Circular],
|
||||
@@ -627,6 +692,11 @@ initialize {
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
"parent": [Circular],
|
||||
@@ -676,7 +746,7 @@ initialize {
|
||||
"parent": [Circular],
|
||||
"prev": Object {
|
||||
"attribs": Object {
|
||||
"class": "",
|
||||
"class": " ",
|
||||
},
|
||||
"children": Array [
|
||||
Object {
|
||||
@@ -698,6 +768,11 @@ initialize {
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
"parent": [Circular],
|
||||
@@ -735,6 +810,11 @@ initialize {
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
"parent": [Circular],
|
||||
@@ -781,7 +861,7 @@ initialize {
|
||||
},
|
||||
Object {
|
||||
"attribs": Object {
|
||||
"class": "",
|
||||
"class": " ",
|
||||
},
|
||||
"children": Array [
|
||||
Object {
|
||||
@@ -803,6 +883,11 @@ initialize {
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
"parent": [Circular],
|
||||
@@ -840,6 +925,11 @@ initialize {
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
"parent": [Circular],
|
||||
@@ -867,7 +957,7 @@ initialize {
|
||||
"namespace": "http://www.w3.org/1999/xhtml",
|
||||
"next": Object {
|
||||
"attribs": Object {
|
||||
"class": "",
|
||||
"class": " ",
|
||||
},
|
||||
"children": Array [
|
||||
Object {
|
||||
@@ -889,6 +979,11 @@ initialize {
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
"parent": [Circular],
|
||||
@@ -926,6 +1021,11 @@ initialize {
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
"parent": [Circular],
|
||||
@@ -965,7 +1065,7 @@ initialize {
|
||||
"parent": [Circular],
|
||||
"prev": Object {
|
||||
"attribs": Object {
|
||||
"class": "",
|
||||
"class": " ",
|
||||
},
|
||||
"children": Array [
|
||||
Object {
|
||||
@@ -987,6 +1087,11 @@ initialize {
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
"parent": [Circular],
|
||||
@@ -1024,6 +1129,11 @@ initialize {
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
"parent": [Circular],
|
||||
@@ -1053,7 +1163,7 @@ initialize {
|
||||
"parent": [Circular],
|
||||
"prev": Object {
|
||||
"attribs": Object {
|
||||
"class": "",
|
||||
"class": " ",
|
||||
},
|
||||
"children": Array [
|
||||
Object {
|
||||
@@ -1075,6 +1185,11 @@ initialize {
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
"parent": [Circular],
|
||||
@@ -1112,6 +1227,11 @@ initialize {
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
"parent": [Circular],
|
||||
@@ -1166,7 +1286,7 @@ initialize {
|
||||
},
|
||||
Object {
|
||||
"attribs": Object {
|
||||
"class": "",
|
||||
"class": " ",
|
||||
},
|
||||
"children": Array [
|
||||
Object {
|
||||
@@ -1188,6 +1308,11 @@ initialize {
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
"parent": [Circular],
|
||||
@@ -1225,6 +1350,11 @@ initialize {
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
"parent": [Circular],
|
||||
@@ -1254,7 +1384,7 @@ initialize {
|
||||
"parent": [Circular],
|
||||
"prev": Object {
|
||||
"attribs": Object {
|
||||
"class": "",
|
||||
"class": " ",
|
||||
},
|
||||
"children": Array [
|
||||
Object {
|
||||
@@ -1276,6 +1406,11 @@ initialize {
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
"parent": [Circular],
|
||||
@@ -1313,6 +1448,11 @@ initialize {
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
"parent": [Circular],
|
||||
@@ -1342,7 +1482,7 @@ initialize {
|
||||
"parent": [Circular],
|
||||
"prev": Object {
|
||||
"attribs": Object {
|
||||
"class": "",
|
||||
"class": " ",
|
||||
},
|
||||
"children": Array [
|
||||
Object {
|
||||
@@ -1364,6 +1504,11 @@ initialize {
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
"parent": [Circular],
|
||||
@@ -1401,6 +1546,11 @@ initialize {
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
"parent": [Circular],
|
||||
@@ -1430,7 +1580,7 @@ initialize {
|
||||
"parent": [Circular],
|
||||
"prev": Object {
|
||||
"attribs": Object {
|
||||
"class": "",
|
||||
"class": " ",
|
||||
},
|
||||
"children": Array [
|
||||
Object {
|
||||
@@ -1452,6 +1602,11 @@ initialize {
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
"parent": [Circular],
|
||||
@@ -1489,6 +1644,11 @@ initialize {
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
"parent": [Circular],
|
||||
@@ -1588,7 +1748,7 @@ exports[`Badge should supoort text 1`] = `
|
||||
initialize {
|
||||
"0": Object {
|
||||
"attribs": Object {
|
||||
"class": "",
|
||||
"class": " ",
|
||||
},
|
||||
"children": Array [
|
||||
Object {
|
||||
@@ -1610,6 +1770,11 @@ initialize {
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
"parent": [Circular],
|
||||
@@ -1647,6 +1812,11 @@ initialize {
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
"parent": [Circular],
|
||||
|
||||
40
components/badge/__tests__/anchor.test.tsx
Normal file
40
components/badge/__tests__/anchor.test.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
import React from 'react'
|
||||
import { mount } from 'enzyme'
|
||||
import { Badge } from 'components'
|
||||
|
||||
describe('BadgeAnchor', () => {
|
||||
it('should render correctly', () => {
|
||||
const wrapper = mount(
|
||||
<Badge.Anchor>
|
||||
<Badge>test</Badge>
|
||||
<a>link</a>
|
||||
</Badge.Anchor>
|
||||
)
|
||||
expect(() => wrapper.unmount()).not.toThrow()
|
||||
})
|
||||
|
||||
it('should be work without Badge', () => {
|
||||
const wrapper = mount(
|
||||
<Badge.Anchor>
|
||||
<a>link</a>
|
||||
</Badge.Anchor>
|
||||
)
|
||||
expect(() => wrapper.unmount()).not.toThrow()
|
||||
})
|
||||
|
||||
it('should be support multiple position', () => {
|
||||
const wrapper = mount(
|
||||
<Badge.Anchor>
|
||||
<Badge>test</Badge>
|
||||
<button>btn</button>
|
||||
</Badge.Anchor>
|
||||
)
|
||||
expect(wrapper.html()).toMatchSnapshot()
|
||||
|
||||
wrapper.setProps({ placement: 'topLeft' })
|
||||
expect(wrapper.html()).toMatchSnapshot()
|
||||
|
||||
wrapper.setProps({ placement: 'bottomRight' })
|
||||
expect(wrapper.html()).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
@@ -52,4 +52,10 @@ describe('Badge', () => {
|
||||
expect(span.props().style).not.toBeUndefined()
|
||||
expect((span.props().style as any).background).toBe('white')
|
||||
})
|
||||
|
||||
it('should hide content when in dot mode', () => {
|
||||
const wrapper = mount(<Badge dot>test-value</Badge>)
|
||||
expect(wrapper.html()).not.toContain('test-value')
|
||||
expect(() => wrapper.unmount()).not.toThrow()
|
||||
})
|
||||
})
|
||||
|
||||
102
components/badge/badge-anchor.tsx
Normal file
102
components/badge/badge-anchor.tsx
Normal file
@@ -0,0 +1,102 @@
|
||||
import React, { useMemo } from 'react'
|
||||
import withDefaults from '../utils/with-defaults'
|
||||
import { pickChild } from '../utils/collections'
|
||||
import { tuple } from '../utils/prop-types'
|
||||
import Badge from './badge'
|
||||
|
||||
const placement = tuple(
|
||||
'topLeft', 'topRight', 'bottomLeft', 'bottomRight',
|
||||
)
|
||||
|
||||
type BadgeAnchorPlacement = typeof placement[number]
|
||||
|
||||
interface Props {
|
||||
placement?: BadgeAnchorPlacement
|
||||
className?: string
|
||||
}
|
||||
|
||||
const defaultProps = {
|
||||
placement: 'topRight' as BadgeAnchorPlacement,
|
||||
className: '',
|
||||
}
|
||||
|
||||
type NativeAttrs = Omit<React.HTMLAttributes<any>, keyof Props>
|
||||
export type BadgeAnchorProps = Props & typeof defaultProps & NativeAttrs
|
||||
|
||||
type TransformStyles = {
|
||||
top?: string
|
||||
bottom?: string
|
||||
left?: string
|
||||
right?: string
|
||||
value: string
|
||||
origin: string
|
||||
}
|
||||
|
||||
const getTransform = (placement: BadgeAnchorPlacement): TransformStyles => {
|
||||
const styles: { [key in BadgeAnchorPlacement]: TransformStyles } = {
|
||||
topLeft: {
|
||||
top: '0', left: '0',
|
||||
value: 'translate(-50%, -50%)',
|
||||
origin: '0% 0%',
|
||||
},
|
||||
topRight: {
|
||||
top: '0', right: '0',
|
||||
value: 'translate(50%, -50%)',
|
||||
origin: '100% 0%',
|
||||
},
|
||||
bottomLeft: {
|
||||
left: '0', bottom: '0',
|
||||
value: 'translate(-50%, 50%)',
|
||||
origin: '0% 100%',
|
||||
},
|
||||
bottomRight: {
|
||||
right: '0', bottom: '0',
|
||||
value: 'translate(50%, 50%)',
|
||||
origin: '100% 100%',
|
||||
}
|
||||
}
|
||||
return styles[placement]
|
||||
}
|
||||
|
||||
const BadgeAnchor: React.FC<React.PropsWithChildren<BadgeAnchorProps>> = ({
|
||||
children, placement,
|
||||
}) => {
|
||||
const [withoutBadgeChildren, badgeChldren] = pickChild(children, Badge)
|
||||
const {
|
||||
top, bottom, left, right, value, origin,
|
||||
} = useMemo(() => getTransform(placement), [placement])
|
||||
|
||||
return (
|
||||
<div className="anchor">
|
||||
{withoutBadgeChildren}
|
||||
<sup>
|
||||
{badgeChldren}
|
||||
</sup>
|
||||
|
||||
<style jsx>{`
|
||||
.anchor {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
vertical-align: middle;
|
||||
flex-shrink: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
sup {
|
||||
position: absolute;
|
||||
top: ${top || 'auto'};
|
||||
left: ${left || 'auto'};
|
||||
right: ${right || 'auto'};
|
||||
bottom: ${bottom || 'auto'};
|
||||
transform: ${value};
|
||||
transform-origin: ${origin};
|
||||
z-index: 1;
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const MemoBadgeAnchor = React.memo(BadgeAnchor)
|
||||
|
||||
export default withDefaults(MemoBadgeAnchor, defaultProps)
|
||||
@@ -1,18 +1,20 @@
|
||||
import React, { useMemo } from 'react'
|
||||
import withDefaults from '../utils/with-defaults'
|
||||
import useTheme from '../styles/use-theme'
|
||||
import { NormalSizes, NormalTypes } from '../utils/prop-types'
|
||||
import { ZeitUIThemesPalette } from 'components/styles/themes'
|
||||
import BadgeAnchor from './badge-anchor'
|
||||
|
||||
interface Props {
|
||||
type?: NormalTypes
|
||||
size?: NormalSizes
|
||||
dot?: boolean
|
||||
className?: string
|
||||
}
|
||||
|
||||
const defaultProps = {
|
||||
type: 'default' as NormalTypes,
|
||||
size: 'medium' as NormalSizes,
|
||||
dot: false,
|
||||
className: '',
|
||||
}
|
||||
|
||||
@@ -41,7 +43,7 @@ const getBgColor = (type: NormalTypes, palette: ZeitUIThemesPalette) => {
|
||||
}
|
||||
|
||||
const Badge: React.FC<React.PropsWithChildren<BadgeProps>> = ({
|
||||
type, size, className, children, ...props
|
||||
type, size, className, children, dot, ...props
|
||||
}) => {
|
||||
const theme = useTheme()
|
||||
const bg = useMemo(() => getBgColor(type, theme.palette), [type, theme.palette])
|
||||
@@ -52,8 +54,8 @@ const Badge: React.FC<React.PropsWithChildren<BadgeProps>> = ({
|
||||
}, [type, theme.palette.background])
|
||||
|
||||
return (
|
||||
<span className={className} {...props}>
|
||||
{children}
|
||||
<span className={`${dot ? 'dot' : ''} ${className}`} {...props}>
|
||||
{!dot && children}
|
||||
<style jsx>{`
|
||||
span {
|
||||
display: inline-block;
|
||||
@@ -67,11 +69,21 @@ const Badge: React.FC<React.PropsWithChildren<BadgeProps>> = ({
|
||||
font-size: ${font};
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.dot {
|
||||
padding: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
`}</style>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
const MemoBadge = React.memo<React.PropsWithChildren<BadgeProps>>(Badge)
|
||||
type MemoBadgeComponent<P = {}> = React.NamedExoticComponent<P> & {
|
||||
Anchor: typeof BadgeAnchor
|
||||
}
|
||||
type ComponentProps = Partial<typeof defaultProps> & Omit<Props, keyof typeof defaultProps> & NativeAttrs
|
||||
|
||||
export default withDefaults(MemoBadge, defaultProps)
|
||||
Badge.defaultProps = defaultProps
|
||||
|
||||
export default React.memo(Badge) as MemoBadgeComponent<ComponentProps>
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import Badge from './badge'
|
||||
import BadgeAnchor from './badge-anchor'
|
||||
|
||||
Badge.Anchor = BadgeAnchor
|
||||
|
||||
export default Badge
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Layout, Playground, Attributes } from 'lib/components'
|
||||
import { Badge, Spacer } from 'components'
|
||||
import { Badge, Spacer, Avatar, Button, Link } from 'components'
|
||||
|
||||
export const meta = {
|
||||
title: 'Badge',
|
||||
@@ -48,16 +48,78 @@ Display an indicator that requires attention.
|
||||
</>
|
||||
`} />
|
||||
|
||||
<Playground
|
||||
title="Anchor"
|
||||
desc="Fix the `Badge` in the designated position."
|
||||
scope={{ Badge, Avatar, Spacer, Button, Link }}
|
||||
code={`
|
||||
<>
|
||||
<Badge.Anchor>
|
||||
<Badge size="mini">10</Badge>
|
||||
<Avatar src="https://zeit.co/api/www/avatar/?u=evilrabbit&s=160" />
|
||||
</Badge.Anchor>
|
||||
<Spacer inline x={1.5} />
|
||||
<Badge.Anchor placement="bottomRight">
|
||||
<Badge size="mini" type="success">10</Badge>
|
||||
<Avatar size={40} isSquare src="https://zeit.co/api/www/avatar/?u=evilrabbit&s=160" />
|
||||
</Badge.Anchor>
|
||||
<Spacer inline x={1.5} />
|
||||
<Badge.Anchor>
|
||||
<Badge size="mini" type="warning">99+</Badge>
|
||||
<Button size="small" auto>Action</Button>
|
||||
</Badge.Anchor>
|
||||
<Spacer inline x={1.5} />
|
||||
<Badge.Anchor>
|
||||
<Badge size="mini" type="error" dot />
|
||||
<Link pure target="_blank" href="https://github.com/zeit-ui/react/">ZEIT UI</Link>
|
||||
</Badge.Anchor>
|
||||
<Spacer inline x={1.5} />
|
||||
<Badge.Anchor>
|
||||
<Badge size="mini" type="error" dot style={{ padding: '7px' }} />
|
||||
<Link pure target="_blank" href="https://github.com/zeit-ui/react/">Share Link</Link>
|
||||
</Badge.Anchor>
|
||||
</>
|
||||
`} />
|
||||
|
||||
<Attributes edit="/pages/en-us/components/badge.mdx">
|
||||
<Attributes.Title>Badge.Props</Attributes.Title>
|
||||
|
||||
| Attribute | Description | Type | Accepted values | Default
|
||||
| ---------- | ---------- | ---- | -------------- | ------ |
|
||||
| **type** | badge type | `NormalTypes` | `'default', 'secondary', 'success', 'warning', 'error'` | `default` |
|
||||
| **size** | badge size | `NormalSizes` | `'mini', 'small', 'medium', 'large'` | `medium` |
|
||||
| **type** | badge type | `NormalTypes` | [NormalTypes](#normaltypes) | `default` |
|
||||
| **size** | badge size | `NormalSizes` | [NormalSizes](#normalsizes) | `medium` |
|
||||
| **dot** | show dot and ignore content | `boolean` | - | `false` |
|
||||
| ... | native props | `HTMLAttributes` | `'alt', 'id', 'className', ...` | - |
|
||||
|
||||
<Attributes.Title>Badge.Anchor.Props</Attributes.Title>
|
||||
|
||||
| Attribute | Description | Type | Accepted values | Default
|
||||
| ---------- | ---------- | ---- | -------------- | ------ |
|
||||
| **placement** | fixe position of Badge | `AnchorPlacement` | [AnchorPlacement](#anchorplacement) | `topRight` |
|
||||
| ... | native props | `HTMLAttributes` | `'alt', 'id', 'className', ...` | - |
|
||||
|
||||
<Attributes.Title>NormalTypes</Attributes.Title>
|
||||
|
||||
```ts
|
||||
type NormalTypes = 'default'
|
||||
| 'secondary'
|
||||
| 'success'
|
||||
| 'warning'
|
||||
| 'error'
|
||||
```
|
||||
|
||||
<Attributes.Title>NormalSizes</Attributes.Title>
|
||||
|
||||
```ts
|
||||
type NormalSizes = 'medium' | 'mini' | 'small' | 'large'
|
||||
```
|
||||
|
||||
<Attributes.Title>AnchorPlacement</Attributes.Title>
|
||||
|
||||
```ts
|
||||
type AnchorPlacement = 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight'
|
||||
```
|
||||
|
||||
</Attributes>
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Layout, Playground, Attributes } from 'lib/components'
|
||||
import { Badge, Spacer } from 'components'
|
||||
import { Badge, Spacer, Button, Link, Avatar } from 'components'
|
||||
|
||||
export const meta = {
|
||||
title: '徽章 Badge',
|
||||
@@ -48,16 +48,78 @@ export const meta = {
|
||||
</>
|
||||
`} />
|
||||
|
||||
<Playground
|
||||
title="锚点"
|
||||
desc="将徽章固定在指定位置。"
|
||||
scope={{ Badge, Avatar, Spacer, Button, Link }}
|
||||
code={`
|
||||
<>
|
||||
<Badge.Anchor>
|
||||
<Badge size="mini">10</Badge>
|
||||
<Avatar src="https://zeit.co/api/www/avatar/?u=evilrabbit&s=160" />
|
||||
</Badge.Anchor>
|
||||
<Spacer inline x={1.5} />
|
||||
<Badge.Anchor placement="bottomRight">
|
||||
<Badge size="mini" type="success">10</Badge>
|
||||
<Avatar size={40} isSquare src="https://zeit.co/api/www/avatar/?u=evilrabbit&s=160" />
|
||||
</Badge.Anchor>
|
||||
<Spacer inline x={1.5} />
|
||||
<Badge.Anchor>
|
||||
<Badge size="mini" type="warning">99+</Badge>
|
||||
<Button size="small" auto>按钮</Button>
|
||||
</Badge.Anchor>
|
||||
<Spacer inline x={1.5} />
|
||||
<Badge.Anchor>
|
||||
<Badge size="mini" type="error" dot />
|
||||
<Link pure target="_blank" href="https://github.com/zeit-ui/react/">组件库</Link>
|
||||
</Badge.Anchor>
|
||||
<Spacer inline x={1.5} />
|
||||
<Badge.Anchor>
|
||||
<Badge size="mini" type="error" dot style={{ padding: '7px' }} />
|
||||
<Link pure target="_blank" href="https://github.com/zeit-ui/react/">分享链接</Link>
|
||||
</Badge.Anchor>
|
||||
</>
|
||||
`} />
|
||||
|
||||
<Attributes edit="/pages/zh-cn/components/badge.mdx">
|
||||
<Attributes.Title>Badge.Props</Attributes.Title>
|
||||
|
||||
| 属性 | 描述 | 类型 | 推荐值 | 默认
|
||||
| ---------- | ---------- | ---- | -------------- | ------ |
|
||||
| **type** | 徽章的类型 | `NormalTypes` | `'default', 'secondary', 'success', 'warning', 'error'` | `default` |
|
||||
| **size** | 徽章的大小 | `NormalSizes` | `'mini', 'small', 'medium', 'large'` | `medium` |
|
||||
| **type** | 徽章的类型 | `NormalTypes` | [NormalTypes](#normaltypes) | `default` |
|
||||
| **size** | 徽章的大小 | `NormalSizes` | [NormalSizes](#normalsizes) | `medium` |
|
||||
| **dot** | 忽略内容并显示圆点 | `boolean` | - | `false` |
|
||||
| ... | 原生属性 | `HTMLAttributes` | `'alt', 'id', 'className', ...` | - |
|
||||
|
||||
<Attributes.Title>Badge.Anchor.Props</Attributes.Title>
|
||||
|
||||
| 属性 | 描述 | 类型 | 推荐值 | 默认
|
||||
| ---------- | ---------- | ---- | -------------- | ------ |
|
||||
| **placement** | 固定徽章的位置 | `AnchorPlacement` | [AnchorPlacement](#anchorplacement) | `topRight` |
|
||||
| ... | 原生属性 | `HTMLAttributes` | `'alt', 'id', 'className', ...` | - |
|
||||
|
||||
<Attributes.Title>NormalTypes</Attributes.Title>
|
||||
|
||||
```ts
|
||||
type NormalTypes = 'default'
|
||||
| 'secondary'
|
||||
| 'success'
|
||||
| 'warning'
|
||||
| 'error'
|
||||
```
|
||||
|
||||
<Attributes.Title>NormalSizes</Attributes.Title>
|
||||
|
||||
```ts
|
||||
type NormalSizes = 'medium' | 'mini' | 'small' | 'large'
|
||||
```
|
||||
|
||||
<Attributes.Title>AnchorPlacement</Attributes.Title>
|
||||
|
||||
```ts
|
||||
type AnchorPlacement = 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight'
|
||||
```
|
||||
|
||||
</Attributes>
|
||||
|
||||
export default ({ children }) => <Layout meta={meta}>{children}</Layout>
|
||||
|
||||
Reference in New Issue
Block a user