mirror of
https://github.com/zhigang1992/react.git
synced 2026-02-07 17:19:15 +08:00
Merge branch 'master' into fix/slider-offset-bug
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -27,3 +27,6 @@ yarn-error.log*
|
||||
.now
|
||||
dist
|
||||
esm
|
||||
examples/**/yarn.lock
|
||||
examples/**/out
|
||||
examples/**/.next
|
||||
|
||||
@@ -4,6 +4,7 @@ exports[`AutoComplete should render correctly 1`] = `
|
||||
<AutoComplete
|
||||
className=""
|
||||
clearable={false}
|
||||
disableFreeSolo={false}
|
||||
disableMatchWidth={false}
|
||||
disabled={false}
|
||||
initialValue=""
|
||||
|
||||
@@ -2,6 +2,7 @@ import React from 'react'
|
||||
import { mount } from 'enzyme'
|
||||
import { AutoComplete } from 'components'
|
||||
import { nativeEvent } from 'tests/utils'
|
||||
import { act } from 'react-dom/test-utils'
|
||||
|
||||
describe('AutoComplete', () => {
|
||||
it('should render correctly', () => {
|
||||
@@ -32,11 +33,13 @@ describe('AutoComplete', () => {
|
||||
expect((input as HTMLInputElement).value).toEqual('value2')
|
||||
})
|
||||
|
||||
it('should render clear icon', () => {
|
||||
it('should render clear icon', async () => {
|
||||
const wrapper = mount(<AutoComplete initialValue="value" />)
|
||||
expect(wrapper.find('svg').length).toBe(0)
|
||||
|
||||
wrapper.setProps({ clearable: true })
|
||||
await act(async () => {
|
||||
wrapper.setProps({ clearable: true })
|
||||
})
|
||||
expect(wrapper.find('svg').length).toBe(1)
|
||||
|
||||
wrapper.find('svg').simulate('click', nativeEvent)
|
||||
@@ -44,11 +47,13 @@ describe('AutoComplete', () => {
|
||||
expect((input as HTMLInputElement).value).toEqual('')
|
||||
})
|
||||
|
||||
it('should reponse width change', () => {
|
||||
it('should reponse width change', async () => {
|
||||
const wrapper = mount(<AutoComplete initialValue="value" width="100px" />)
|
||||
expect(wrapper.prop('width')).toEqual('100px')
|
||||
await act(async () => {
|
||||
wrapper.setProps({ width: '200px' })
|
||||
})
|
||||
|
||||
wrapper.setProps({ width: '200px' })
|
||||
expect(wrapper.prop('width')).toEqual('200px')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import React from 'react'
|
||||
import { mount, render } from 'enzyme'
|
||||
import { AutoComplete } from 'components'
|
||||
import { nativeEvent } from 'tests/utils'
|
||||
import { nativeEvent, updateWrapper } from 'tests/utils'
|
||||
import { act } from 'react-dom/test-utils'
|
||||
const mockOptions = [{ label: 'London', value: 'london' }]
|
||||
|
||||
describe('AutoComplete Search', () => {
|
||||
@@ -33,9 +34,11 @@ describe('AutoComplete Search', () => {
|
||||
expect(value).not.toEqual('london')
|
||||
})
|
||||
|
||||
it('should render searching component', () => {
|
||||
it('should render searching component', async () => {
|
||||
let wrapper = mount(<AutoComplete searching={false} options={mockOptions} />)
|
||||
wrapper.setProps({ searching: true })
|
||||
await act(async () => {
|
||||
wrapper.setProps({ searching: true })
|
||||
})
|
||||
wrapper.find('input').at(0).simulate('focus')
|
||||
let dropdown = wrapper.find('.auto-complete-dropdown')
|
||||
expect(dropdown.text()).not.toContain('london')
|
||||
@@ -136,4 +139,15 @@ describe('AutoComplete Search', () => {
|
||||
const wrapper = mount(<AutoComplete options={[]} />)
|
||||
expect(() => wrapper.unmount()).not.toThrow()
|
||||
})
|
||||
|
||||
it('value should be reset when freeSolo disabled', async () => {
|
||||
const wrapper = mount(<AutoComplete initialValue="value" disableFreeSolo />)
|
||||
const input = wrapper.find('input').at(0)
|
||||
input.simulate('focus')
|
||||
input.simulate('change', { target: { value: 'test' } })
|
||||
expect((input.getDOMNode() as HTMLInputElement).value).toEqual('test')
|
||||
input.simulate('blur')
|
||||
await updateWrapper(wrapper, 200)
|
||||
expect((input.getDOMNode() as HTMLInputElement).value).toEqual('value')
|
||||
})
|
||||
})
|
||||
|
||||
60
components/auto-complete/__tests__/use-input.test.tsx
Normal file
60
components/auto-complete/__tests__/use-input.test.tsx
Normal file
@@ -0,0 +1,60 @@
|
||||
import React, { useEffect } from 'react'
|
||||
import { mount } from 'enzyme'
|
||||
import { AutoComplete, useInput } from 'components'
|
||||
|
||||
describe('UseInput', () => {
|
||||
it('should follow change with use-input', () => {
|
||||
let log = ''
|
||||
const logSpy = jest.spyOn(console, 'log').mockImplementation(msg => (log = msg))
|
||||
const MockInput: React.FC<{ value?: string }> = ({ value }) => {
|
||||
const { state, setState, bindings } = useInput('')
|
||||
useEffect(() => {
|
||||
if (value) setState(value)
|
||||
}, [value])
|
||||
useEffect(() => {
|
||||
if (state) console.log(state)
|
||||
}, [state])
|
||||
return <AutoComplete {...bindings} />
|
||||
}
|
||||
|
||||
const wrapper = mount(<MockInput />)
|
||||
wrapper.setProps({ value: 'test' })
|
||||
const input = wrapper.find('input').at(0).getDOMNode() as HTMLInputElement
|
||||
|
||||
expect(input.value).toEqual('test')
|
||||
expect(log).toContain('test')
|
||||
|
||||
log = ''
|
||||
wrapper
|
||||
.find('input')
|
||||
.at(0)
|
||||
.simulate('change', { target: { value: 'test-change' } })
|
||||
expect(log).toContain('test-change')
|
||||
logSpy.mockRestore()
|
||||
})
|
||||
|
||||
it('should follow change with use-input', () => {
|
||||
const MockInput: React.FC<{ value?: string; resetValue?: boolean }> = ({
|
||||
value,
|
||||
resetValue,
|
||||
}) => {
|
||||
const { reset, setState, bindings } = useInput('')
|
||||
useEffect(() => {
|
||||
if (value) setState(value)
|
||||
}, [value])
|
||||
useEffect(() => {
|
||||
if (resetValue) reset()
|
||||
}, [resetValue])
|
||||
return <AutoComplete {...bindings} />
|
||||
}
|
||||
|
||||
const wrapper = mount(<MockInput />)
|
||||
wrapper.setProps({ value: 'test' })
|
||||
let input = wrapper.find('input').at(0).getDOMNode() as HTMLInputElement
|
||||
expect(input.value).toEqual('test')
|
||||
|
||||
wrapper.setProps({ resetValue: true })
|
||||
input = wrapper.find('input').at(0).getDOMNode() as HTMLInputElement
|
||||
expect(input.value).toEqual('')
|
||||
})
|
||||
})
|
||||
@@ -28,9 +28,10 @@ const AutoCompleteItem: React.FC<React.PropsWithChildren<AutoCompleteItemProps>>
|
||||
children,
|
||||
}) => {
|
||||
const theme = useTheme()
|
||||
const { value, updateValue, size } = useAutoCompleteContext()
|
||||
const { value, updateValue, size, updateVisible } = useAutoCompleteContext()
|
||||
const selectHandler = () => {
|
||||
updateValue && updateValue(identValue)
|
||||
updateVisible && updateVisible(false)
|
||||
}
|
||||
|
||||
const isActive = useMemo(() => value === identValue, [identValue, value])
|
||||
@@ -38,7 +39,7 @@ const AutoCompleteItem: React.FC<React.PropsWithChildren<AutoCompleteItemProps>>
|
||||
|
||||
return (
|
||||
<div className={`item ${isActive ? 'active' : ''}`} onClick={selectHandler}>
|
||||
<Ellipsis>{children}</Ellipsis>
|
||||
<Ellipsis height={`calc(1.688 * ${theme.layout.gap})`}>{children}</Ellipsis>
|
||||
<style jsx>{`
|
||||
.item {
|
||||
display: flex;
|
||||
@@ -47,8 +48,8 @@ const AutoCompleteItem: React.FC<React.PropsWithChildren<AutoCompleteItemProps>>
|
||||
font-weight: normal;
|
||||
white-space: pre;
|
||||
font-size: ${fontSize};
|
||||
padding: ${theme.layout.gapHalf};
|
||||
line-height: 1.2;
|
||||
padding: 0 ${theme.layout.gapHalf};
|
||||
height: calc(1.688 * ${theme.layout.gap});
|
||||
background-color: ${theme.palette.background};
|
||||
color: ${theme.palette.foreground};
|
||||
user-select: none;
|
||||
|
||||
@@ -8,6 +8,7 @@ import { AutoCompleteContext, AutoCompleteConfig } from './auto-complete-context
|
||||
import { NormalSizes, NormalTypes } from '../utils/prop-types'
|
||||
import Loading from '../loading'
|
||||
import { pickChild } from '../utils/collections'
|
||||
import useCurrentState from '../utils/use-current-state'
|
||||
|
||||
export type AutoCompleteOption = {
|
||||
label: string
|
||||
@@ -31,6 +32,7 @@ interface Props {
|
||||
dropdownClassName?: string
|
||||
dropdownStyle?: object
|
||||
disableMatchWidth?: boolean
|
||||
disableFreeSolo?: boolean
|
||||
className?: string
|
||||
}
|
||||
|
||||
@@ -41,6 +43,7 @@ const defaultProps = {
|
||||
clearable: false,
|
||||
size: 'medium' as NormalSizes,
|
||||
disableMatchWidth: false,
|
||||
disableFreeSolo: false,
|
||||
className: '',
|
||||
}
|
||||
|
||||
@@ -83,11 +86,16 @@ const AutoComplete: React.FC<React.PropsWithChildren<AutoCompleteProps>> = ({
|
||||
dropdownClassName,
|
||||
dropdownStyle,
|
||||
disableMatchWidth,
|
||||
disableFreeSolo,
|
||||
...props
|
||||
}) => {
|
||||
const ref = useRef<HTMLDivElement>(null)
|
||||
const [state, setState] = useState<string>(customInitialValue)
|
||||
const inputRef = useRef<HTMLInputElement>(null)
|
||||
const resetTimer = useRef<number>()
|
||||
const [state, setState, stateRef] = useCurrentState<string>(customInitialValue)
|
||||
const [selectVal, setSelectVal] = useState<string>(customInitialValue)
|
||||
const [visible, setVisible] = useState<boolean>(false)
|
||||
|
||||
const [, searchChild] = pickChild(children, AutoCompleteSearching)
|
||||
const [, emptyChild] = pickChild(children, AutoCompleteEmpty)
|
||||
const autoCompleteItems = useMemo(() => {
|
||||
@@ -110,14 +118,24 @@ const AutoComplete: React.FC<React.PropsWithChildren<AutoCompleteProps>> = ({
|
||||
|
||||
const updateValue = (val: string) => {
|
||||
if (disabled) return
|
||||
setSelectVal(val)
|
||||
onSelect && onSelect(val)
|
||||
setState(val)
|
||||
inputRef.current && inputRef.current.focus()
|
||||
}
|
||||
const updateVisible = (next: boolean) => setVisible(next)
|
||||
const onInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setVisible(true)
|
||||
onSearch && onSearch(event.target.value)
|
||||
setState(event.target.value)
|
||||
}
|
||||
const resetInputValue = () => {
|
||||
if (!disableFreeSolo) return
|
||||
if (!state || state === '') return
|
||||
if (state !== selectVal) {
|
||||
setState(selectVal)
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
onChange && onChange(state)
|
||||
@@ -140,9 +158,15 @@ const AutoComplete: React.FC<React.PropsWithChildren<AutoCompleteProps>> = ({
|
||||
)
|
||||
|
||||
const toggleFocusHandler = (next: boolean) => {
|
||||
clearTimeout(resetTimer.current)
|
||||
setVisible(next)
|
||||
if (next) {
|
||||
onSearch && onSearch(state)
|
||||
onSearch && onSearch(stateRef.current)
|
||||
} else {
|
||||
resetTimer.current = window.setTimeout(() => {
|
||||
resetInputValue()
|
||||
clearTimeout(resetTimer.current)
|
||||
}, 100)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,6 +181,7 @@ const AutoComplete: React.FC<React.PropsWithChildren<AutoCompleteProps>> = ({
|
||||
<AutoCompleteContext.Provider value={initialValue}>
|
||||
<div ref={ref} className="auto-complete">
|
||||
<Input
|
||||
ref={inputRef}
|
||||
size={size}
|
||||
status={status}
|
||||
onChange={onInputChange}
|
||||
|
||||
@@ -316,7 +316,7 @@ initialize {
|
||||
font-variant: tabular-nums;
|
||||
line-height: 1;
|
||||
vertical-align: middle;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
color: white;
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
@@ -358,7 +358,7 @@ initialize {
|
||||
font-variant: tabular-nums;
|
||||
line-height: 1;
|
||||
vertical-align: middle;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
color: white;
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
@@ -645,7 +645,7 @@ initialize {
|
||||
font-variant: tabular-nums;
|
||||
line-height: 1;
|
||||
vertical-align: middle;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
color: white;
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
@@ -687,7 +687,7 @@ initialize {
|
||||
font-variant: tabular-nums;
|
||||
line-height: 1;
|
||||
vertical-align: middle;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
color: white;
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
@@ -974,7 +974,7 @@ initialize {
|
||||
font-variant: tabular-nums;
|
||||
line-height: 1;
|
||||
vertical-align: middle;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
color: white;
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
@@ -1016,7 +1016,7 @@ initialize {
|
||||
font-variant: tabular-nums;
|
||||
line-height: 1;
|
||||
vertical-align: middle;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
color: white;
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
@@ -1303,7 +1303,7 @@ initialize {
|
||||
font-variant: tabular-nums;
|
||||
line-height: 1;
|
||||
vertical-align: middle;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
color: white;
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
@@ -1345,7 +1345,7 @@ initialize {
|
||||
font-variant: tabular-nums;
|
||||
line-height: 1;
|
||||
vertical-align: middle;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
color: white;
|
||||
font-size: .875rem;
|
||||
border: 0;
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Breadcrumbs should redefined all separators 1`] = `
|
||||
"<nav class=\\"\\"><span class=\\"breadcrums-item \\">test-1</span><div class=\\"separator \\">*<style>
|
||||
.separator {
|
||||
display: inline-flex;
|
||||
margin: 0 8px;
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
align-items: center;
|
||||
}
|
||||
</style></div><span class=\\"breadcrums-item \\">test-2</span><style>
|
||||
nav {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
line-height: inherit;
|
||||
color: #888;
|
||||
font-size: 1rem;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
nav :global(.link:hover) {
|
||||
color: rgba(0, 112, 243, 0.85);
|
||||
}
|
||||
|
||||
nav > :global(span:last-of-type) {
|
||||
color: #444;
|
||||
}
|
||||
|
||||
nav > :global(.separator:last-child) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
nav :global(svg) {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
margin: 0 4px;
|
||||
}
|
||||
|
||||
nav :global(.breadcrums-item) {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
</style></nav>"
|
||||
`;
|
||||
|
||||
exports[`Breadcrumbs should render correctly 1`] = `
|
||||
"<nav class=\\"\\"><span class=\\"breadcrums-item \\">test-1</span><style>
|
||||
nav {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
line-height: inherit;
|
||||
color: #888;
|
||||
font-size: 1rem;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
nav :global(.link:hover) {
|
||||
color: rgba(0, 112, 243, 0.85);
|
||||
}
|
||||
|
||||
nav > :global(span:last-of-type) {
|
||||
color: #444;
|
||||
}
|
||||
|
||||
nav > :global(.separator:last-child) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
nav :global(svg) {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
margin: 0 4px;
|
||||
}
|
||||
|
||||
nav :global(.breadcrums-item) {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
</style></nav>"
|
||||
`;
|
||||
75
components/breadcrumbs/__tests__/breadcrumbs.test.tsx
Normal file
75
components/breadcrumbs/__tests__/breadcrumbs.test.tsx
Normal file
@@ -0,0 +1,75 @@
|
||||
import React from 'react'
|
||||
import { mount } from 'enzyme'
|
||||
import { Breadcrumbs } from 'components'
|
||||
|
||||
describe('Breadcrumbs', () => {
|
||||
it('should render correctly', () => {
|
||||
const wrapper = mount(
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.Item>test-1</Breadcrumbs.Item>
|
||||
</Breadcrumbs>,
|
||||
)
|
||||
expect(wrapper.html()).toMatchSnapshot()
|
||||
expect(() => wrapper.unmount()).not.toThrow()
|
||||
})
|
||||
|
||||
it('should redefined all separators', () => {
|
||||
const wrapper = mount(
|
||||
<Breadcrumbs separator="*">
|
||||
<Breadcrumbs.Item>test-1</Breadcrumbs.Item>
|
||||
<Breadcrumbs.Item>test-2</Breadcrumbs.Item>
|
||||
</Breadcrumbs>,
|
||||
)
|
||||
expect(wrapper.html()).toMatchSnapshot()
|
||||
expect(wrapper.html()).toContain('*')
|
||||
expect(() => wrapper.unmount()).not.toThrow()
|
||||
})
|
||||
|
||||
it('the specified separator should be redefined', () => {
|
||||
const wrapper = mount(
|
||||
<Breadcrumbs separator="*">
|
||||
<Breadcrumbs.Item>test-1</Breadcrumbs.Item>
|
||||
<Breadcrumbs.Separator>%</Breadcrumbs.Separator>
|
||||
<Breadcrumbs.Item>test-2</Breadcrumbs.Item>
|
||||
</Breadcrumbs>,
|
||||
)
|
||||
expect(wrapper.html()).toContain('%')
|
||||
})
|
||||
|
||||
it('should render string when href missing', () => {
|
||||
let wrapper = mount(
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.Item>test-1</Breadcrumbs.Item>
|
||||
</Breadcrumbs>,
|
||||
)
|
||||
let dom = wrapper.find('.breadcrums-item').at(0).getDOMNode()
|
||||
expect(dom.tagName).toEqual('SPAN')
|
||||
|
||||
wrapper = mount(
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.Item href="">test-1</Breadcrumbs.Item>
|
||||
</Breadcrumbs>,
|
||||
)
|
||||
dom = wrapper.find('.breadcrums-item').at(0).getDOMNode()
|
||||
expect(dom.tagName).toEqual('A')
|
||||
|
||||
wrapper = mount(
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.Item nextLink>test-1</Breadcrumbs.Item>
|
||||
</Breadcrumbs>,
|
||||
)
|
||||
dom = wrapper.find('.breadcrums-item').at(0).getDOMNode()
|
||||
expect(dom.tagName).toEqual('A')
|
||||
})
|
||||
|
||||
it('should trigger click event', () => {
|
||||
const handler = jest.fn()
|
||||
const wrapper = mount(
|
||||
<Breadcrumbs>
|
||||
<Breadcrumbs.Item onClick={handler}>test-1</Breadcrumbs.Item>
|
||||
</Breadcrumbs>,
|
||||
)
|
||||
wrapper.find('.breadcrums-item').at(0).simulate('click')
|
||||
expect(handler).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
61
components/breadcrumbs/breadcrumbs-item.tsx
Normal file
61
components/breadcrumbs/breadcrumbs-item.tsx
Normal file
@@ -0,0 +1,61 @@
|
||||
import Link from '../link'
|
||||
import { Props as LinkBasicProps } from '../link/link'
|
||||
import React, { useMemo } from 'react'
|
||||
import withDefaults from '../utils/with-defaults'
|
||||
import { pickChild } from '../utils/collections'
|
||||
import BreadcrumbsSeparator from './breadcrumbs-separator'
|
||||
|
||||
interface Props {
|
||||
href?: string
|
||||
nextLink?: boolean
|
||||
onClick?: (event: React.MouseEvent) => void
|
||||
className?: string
|
||||
}
|
||||
|
||||
const defaultProps = {
|
||||
nextLink: false,
|
||||
className: '',
|
||||
}
|
||||
|
||||
type NativeAttrs = Omit<React.AnchorHTMLAttributes<any>, keyof Props>
|
||||
type NativeLinkAttrs = Omit<NativeAttrs, keyof LinkBasicProps>
|
||||
export type BreadcrumbsProps = Props & typeof defaultProps & NativeLinkAttrs
|
||||
|
||||
const BreadcrumbsItem = React.forwardRef<
|
||||
HTMLAnchorElement,
|
||||
React.PropsWithChildren<BreadcrumbsProps>
|
||||
>(
|
||||
(
|
||||
{ href, nextLink, onClick, children, className, ...props },
|
||||
ref: React.Ref<HTMLAnchorElement>,
|
||||
) => {
|
||||
const isLink = useMemo(() => href !== undefined || nextLink, [href, nextLink])
|
||||
const [withoutSepChildren] = pickChild(children, BreadcrumbsSeparator)
|
||||
const clickHandler = (event: React.MouseEvent) => {
|
||||
onClick && onClick(event)
|
||||
}
|
||||
|
||||
if (!isLink) {
|
||||
return (
|
||||
<span className={`breadcrums-item ${className}`} onClick={clickHandler}>
|
||||
{withoutSepChildren}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Link
|
||||
className={`breadcrums-item ${className}`}
|
||||
href={href}
|
||||
onClick={clickHandler}
|
||||
ref={ref}
|
||||
{...props}>
|
||||
{withoutSepChildren}
|
||||
</Link>
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
const MemoBreadcrumbsItem = React.memo(BreadcrumbsItem)
|
||||
|
||||
export default withDefaults(MemoBreadcrumbsItem, defaultProps)
|
||||
37
components/breadcrumbs/breadcrumbs-separator.tsx
Normal file
37
components/breadcrumbs/breadcrumbs-separator.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import React from 'react'
|
||||
import withDefaults from '../utils/with-defaults'
|
||||
|
||||
interface Props {
|
||||
className?: string
|
||||
}
|
||||
|
||||
const defaultProps = {
|
||||
className: '',
|
||||
}
|
||||
|
||||
type NativeAttrs = Omit<React.HTMLAttributes<any>, keyof Props>
|
||||
export type BreadcrumbsProps = Props & typeof defaultProps & NativeAttrs
|
||||
|
||||
const BreadcrumbsSeparator: React.FC<React.PropsWithChildren<BreadcrumbsProps>> = ({
|
||||
children,
|
||||
className,
|
||||
}) => {
|
||||
return (
|
||||
<div className={`separator ${className}`}>
|
||||
{children}
|
||||
<style jsx>{`
|
||||
.separator {
|
||||
display: inline-flex;
|
||||
margin: 0 8px;
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
align-items: center;
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const MemoBreadcrumbsSeparator = React.memo(BreadcrumbsSeparator)
|
||||
|
||||
export default withDefaults(MemoBreadcrumbsSeparator, defaultProps)
|
||||
114
components/breadcrumbs/breadcrumbs.tsx
Normal file
114
components/breadcrumbs/breadcrumbs.tsx
Normal file
@@ -0,0 +1,114 @@
|
||||
import React, { ReactNode, useMemo } from 'react'
|
||||
import useTheme from '../styles/use-theme'
|
||||
import BreadcrumbsItem from './breadcrumbs-item'
|
||||
import BreadcrumbsSeparator from './breadcrumbs-separator'
|
||||
import { addColorAlpha } from '../utils/color'
|
||||
import { NormalSizes } from '../utils/prop-types'
|
||||
|
||||
interface Props {
|
||||
size: NormalSizes
|
||||
separator?: string | ReactNode
|
||||
className?: string
|
||||
}
|
||||
|
||||
const defaultProps = {
|
||||
size: 'medium' as NormalSizes,
|
||||
separator: '/',
|
||||
className: '',
|
||||
}
|
||||
|
||||
type NativeAttrs = Omit<React.HTMLAttributes<any>, keyof Props>
|
||||
export type BreadcrumbsProps = Props & typeof defaultProps & NativeAttrs
|
||||
|
||||
const getSize = (size: NormalSizes) => {
|
||||
const sizes: { [key in NormalSizes]: string } = {
|
||||
mini: '.75rem',
|
||||
small: '.875rem',
|
||||
medium: '1rem',
|
||||
large: '1.125rem',
|
||||
}
|
||||
return sizes[size]
|
||||
}
|
||||
|
||||
const Breadcrumbs: React.FC<React.PropsWithChildren<BreadcrumbsProps>> = ({
|
||||
size,
|
||||
separator,
|
||||
children,
|
||||
className,
|
||||
}) => {
|
||||
const theme = useTheme()
|
||||
const fontSize = useMemo(() => getSize(size), [size])
|
||||
const hoverColor = useMemo(() => {
|
||||
return addColorAlpha(theme.palette.link, 0.85)
|
||||
}, [theme.palette.link])
|
||||
|
||||
const childrenArray = React.Children.toArray(children)
|
||||
const withSeparatorChildren = childrenArray.map((item, index) => {
|
||||
if (!React.isValidElement(item)) return item
|
||||
const last = childrenArray[index - 1]
|
||||
const lastIsSeparator = React.isValidElement(last) && last.type === BreadcrumbsSeparator
|
||||
const currentIsSeparator = item.type === BreadcrumbsSeparator
|
||||
if (!lastIsSeparator && !currentIsSeparator && index > 0) {
|
||||
return (
|
||||
<React.Fragment key={index}>
|
||||
<BreadcrumbsSeparator>{separator}</BreadcrumbsSeparator>
|
||||
{item}
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
return item
|
||||
})
|
||||
|
||||
return (
|
||||
<nav className={className}>
|
||||
{withSeparatorChildren}
|
||||
<style jsx>{`
|
||||
nav {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
line-height: inherit;
|
||||
color: ${theme.palette.accents_4};
|
||||
font-size: ${fontSize};
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
nav :global(.link:hover) {
|
||||
color: ${hoverColor};
|
||||
}
|
||||
|
||||
nav > :global(span:last-of-type) {
|
||||
color: ${theme.palette.accents_6};
|
||||
}
|
||||
|
||||
nav > :global(.separator:last-child) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
nav :global(svg) {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
margin: 0 4px;
|
||||
}
|
||||
|
||||
nav :global(.breadcrums-item) {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
`}</style>
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
|
||||
type MemoBreadcrumbsComponent<P = {}> = React.NamedExoticComponent<P> & {
|
||||
Item: typeof BreadcrumbsItem
|
||||
Separator: typeof BreadcrumbsSeparator
|
||||
}
|
||||
type ComponentProps = Partial<typeof defaultProps> &
|
||||
Omit<Props, keyof typeof defaultProps> &
|
||||
NativeAttrs
|
||||
|
||||
Breadcrumbs.defaultProps = defaultProps
|
||||
|
||||
export default React.memo(Breadcrumbs) as MemoBreadcrumbsComponent<ComponentProps>
|
||||
8
components/breadcrumbs/index.ts
Normal file
8
components/breadcrumbs/index.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import Breadcrumbs from './breadcrumbs'
|
||||
import BreadcrumbsItem from './breadcrumbs-item'
|
||||
import BreadcrumbsSeparator from './breadcrumbs-separator'
|
||||
|
||||
Breadcrumbs.Item = BreadcrumbsItem
|
||||
Breadcrumbs.Separator = BreadcrumbsSeparator
|
||||
|
||||
export default Breadcrumbs
|
||||
@@ -301,8 +301,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #f49b0b;
|
||||
background-color: #f49b0b;
|
||||
border-color: #ab570a;
|
||||
background-color: #ab570a;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -353,8 +353,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #f49b0b;
|
||||
background-color: #f49b0b;
|
||||
border-color: #ab570a;
|
||||
background-color: #ab570a;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -407,7 +407,7 @@ initialize {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
border: none;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
height: 2.5rem;
|
||||
@@ -417,8 +417,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #c00;
|
||||
background-color: #c00;
|
||||
border-color: #c50000;
|
||||
background-color: #c50000;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -459,7 +459,7 @@ initialize {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
border: none;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
height: 2.5rem;
|
||||
@@ -469,8 +469,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #c00;
|
||||
background-color: #c00;
|
||||
border-color: #c50000;
|
||||
background-color: #c50000;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -544,7 +544,7 @@ initialize {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
border: none;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
height: 2.5rem;
|
||||
@@ -554,8 +554,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #c00;
|
||||
background-color: #c00;
|
||||
border-color: #c50000;
|
||||
background-color: #c50000;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -596,7 +596,7 @@ initialize {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
border: none;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
height: 2.5rem;
|
||||
@@ -606,8 +606,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #c00;
|
||||
background-color: #c00;
|
||||
border-color: #c50000;
|
||||
background-color: #c50000;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -672,8 +672,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #f49b0b;
|
||||
background-color: #f49b0b;
|
||||
border-color: #ab570a;
|
||||
background-color: #ab570a;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -724,8 +724,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #f49b0b;
|
||||
background-color: #f49b0b;
|
||||
border-color: #ab570a;
|
||||
background-color: #ab570a;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -832,8 +832,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #f49b0b;
|
||||
background-color: #f49b0b;
|
||||
border-color: #ab570a;
|
||||
background-color: #ab570a;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -884,8 +884,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #f49b0b;
|
||||
background-color: #f49b0b;
|
||||
border-color: #ab570a;
|
||||
background-color: #ab570a;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -938,7 +938,7 @@ initialize {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
border: none;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
height: 2.5rem;
|
||||
@@ -948,8 +948,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #c00;
|
||||
background-color: #c00;
|
||||
border-color: #c50000;
|
||||
background-color: #c50000;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -990,7 +990,7 @@ initialize {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
border: none;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
height: 2.5rem;
|
||||
@@ -1000,8 +1000,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #c00;
|
||||
background-color: #c00;
|
||||
border-color: #c50000;
|
||||
background-color: #c50000;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -1075,7 +1075,7 @@ initialize {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
border: none;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
height: 2.5rem;
|
||||
@@ -1085,8 +1085,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #c00;
|
||||
background-color: #c00;
|
||||
border-color: #c50000;
|
||||
background-color: #c50000;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -1127,7 +1127,7 @@ initialize {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
border: none;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
height: 2.5rem;
|
||||
@@ -1137,8 +1137,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #c00;
|
||||
background-color: #c00;
|
||||
border-color: #c50000;
|
||||
background-color: #c50000;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -1203,8 +1203,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #f49b0b;
|
||||
background-color: #f49b0b;
|
||||
border-color: #ab570a;
|
||||
background-color: #ab570a;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -1255,8 +1255,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #f49b0b;
|
||||
background-color: #f49b0b;
|
||||
border-color: #ab570a;
|
||||
background-color: #ab570a;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -1733,8 +1733,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #f49b0b;
|
||||
background-color: #f49b0b;
|
||||
border-color: #ab570a;
|
||||
background-color: #ab570a;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -1785,8 +1785,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #f49b0b;
|
||||
background-color: #f49b0b;
|
||||
border-color: #ab570a;
|
||||
background-color: #ab570a;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -1839,7 +1839,7 @@ initialize {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
border: none;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
height: 2.5rem;
|
||||
@@ -1849,8 +1849,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #c00;
|
||||
background-color: #c00;
|
||||
border-color: #c50000;
|
||||
background-color: #c50000;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -1891,7 +1891,7 @@ initialize {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
border: none;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
height: 2.5rem;
|
||||
@@ -1901,8 +1901,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #c00;
|
||||
background-color: #c00;
|
||||
border-color: #c50000;
|
||||
background-color: #c50000;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -1976,7 +1976,7 @@ initialize {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
border: none;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
height: 2.5rem;
|
||||
@@ -1986,8 +1986,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #c00;
|
||||
background-color: #c00;
|
||||
border-color: #c50000;
|
||||
background-color: #c50000;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -2028,7 +2028,7 @@ initialize {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
border: none;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
height: 2.5rem;
|
||||
@@ -2038,8 +2038,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #c00;
|
||||
background-color: #c00;
|
||||
border-color: #c50000;
|
||||
background-color: #c50000;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -2104,8 +2104,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #f49b0b;
|
||||
background-color: #f49b0b;
|
||||
border-color: #ab570a;
|
||||
background-color: #ab570a;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -2156,8 +2156,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #f49b0b;
|
||||
background-color: #f49b0b;
|
||||
border-color: #ab570a;
|
||||
background-color: #ab570a;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -2264,8 +2264,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #f49b0b;
|
||||
background-color: #f49b0b;
|
||||
border-color: #ab570a;
|
||||
background-color: #ab570a;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -2316,8 +2316,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #f49b0b;
|
||||
background-color: #f49b0b;
|
||||
border-color: #ab570a;
|
||||
background-color: #ab570a;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -2370,7 +2370,7 @@ initialize {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
border: none;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
height: 2.5rem;
|
||||
@@ -2380,8 +2380,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #c00;
|
||||
background-color: #c00;
|
||||
border-color: #c50000;
|
||||
background-color: #c50000;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -2422,7 +2422,7 @@ initialize {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
border: none;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
height: 2.5rem;
|
||||
@@ -2432,8 +2432,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #c00;
|
||||
background-color: #c00;
|
||||
border-color: #c50000;
|
||||
background-color: #c50000;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -2507,7 +2507,7 @@ initialize {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
border: none;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
height: 2.5rem;
|
||||
@@ -2517,8 +2517,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #c00;
|
||||
background-color: #c00;
|
||||
border-color: #c50000;
|
||||
background-color: #c50000;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -2559,7 +2559,7 @@ initialize {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
border: none;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
height: 2.5rem;
|
||||
@@ -2569,8 +2569,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #c00;
|
||||
background-color: #c00;
|
||||
border-color: #c50000;
|
||||
background-color: #c50000;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -2635,8 +2635,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #f49b0b;
|
||||
background-color: #f49b0b;
|
||||
border-color: #ab570a;
|
||||
background-color: #ab570a;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -2687,8 +2687,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #f49b0b;
|
||||
background-color: #f49b0b;
|
||||
border-color: #ab570a;
|
||||
background-color: #ab570a;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -3356,8 +3356,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #f49b0b;
|
||||
background-color: #f49b0b;
|
||||
border-color: #ab570a;
|
||||
background-color: #ab570a;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -3408,8 +3408,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #f49b0b;
|
||||
background-color: #f49b0b;
|
||||
border-color: #ab570a;
|
||||
background-color: #ab570a;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -3462,7 +3462,7 @@ initialize {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
border: none;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
height: 2.5rem;
|
||||
@@ -3472,8 +3472,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #c00;
|
||||
background-color: #c00;
|
||||
border-color: #c50000;
|
||||
background-color: #c50000;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -3514,7 +3514,7 @@ initialize {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
border: none;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
height: 2.5rem;
|
||||
@@ -3524,8 +3524,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #c00;
|
||||
background-color: #c00;
|
||||
border-color: #c50000;
|
||||
background-color: #c50000;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -3599,7 +3599,7 @@ initialize {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
border: none;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
height: 2.5rem;
|
||||
@@ -3609,8 +3609,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #c00;
|
||||
background-color: #c00;
|
||||
border-color: #c50000;
|
||||
background-color: #c50000;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -3651,7 +3651,7 @@ initialize {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
border: none;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
height: 2.5rem;
|
||||
@@ -3661,8 +3661,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #c00;
|
||||
background-color: #c00;
|
||||
border-color: #c50000;
|
||||
background-color: #c50000;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -3727,8 +3727,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #f49b0b;
|
||||
background-color: #f49b0b;
|
||||
border-color: #ab570a;
|
||||
background-color: #ab570a;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -3779,8 +3779,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #f49b0b;
|
||||
background-color: #f49b0b;
|
||||
border-color: #ab570a;
|
||||
background-color: #ab570a;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -3887,8 +3887,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #f49b0b;
|
||||
background-color: #f49b0b;
|
||||
border-color: #ab570a;
|
||||
background-color: #ab570a;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -3939,8 +3939,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #f49b0b;
|
||||
background-color: #f49b0b;
|
||||
border-color: #ab570a;
|
||||
background-color: #ab570a;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -3993,7 +3993,7 @@ initialize {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
border: none;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
height: 2.5rem;
|
||||
@@ -4003,8 +4003,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #c00;
|
||||
background-color: #c00;
|
||||
border-color: #c50000;
|
||||
background-color: #c50000;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -4045,7 +4045,7 @@ initialize {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
border: none;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
height: 2.5rem;
|
||||
@@ -4055,8 +4055,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #c00;
|
||||
background-color: #c00;
|
||||
border-color: #c50000;
|
||||
background-color: #c50000;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -4130,7 +4130,7 @@ initialize {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
border: none;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
height: 2.5rem;
|
||||
@@ -4140,8 +4140,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #c00;
|
||||
background-color: #c00;
|
||||
border-color: #c50000;
|
||||
background-color: #c50000;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -4182,7 +4182,7 @@ initialize {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
border: none;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
height: 2.5rem;
|
||||
@@ -4192,8 +4192,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #c00;
|
||||
background-color: #c00;
|
||||
border-color: #c50000;
|
||||
background-color: #c50000;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -4258,8 +4258,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #f49b0b;
|
||||
background-color: #f49b0b;
|
||||
border-color: #ab570a;
|
||||
background-color: #ab570a;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
@@ -4310,8 +4310,8 @@ initialize {
|
||||
}
|
||||
|
||||
button:hover {
|
||||
border-color: #f49b0b;
|
||||
background-color: #f49b0b;
|
||||
border-color: #ab570a;
|
||||
background-color: #ab570a;
|
||||
}
|
||||
",
|
||||
"next": null,
|
||||
|
||||
@@ -176,7 +176,7 @@ initialize {
|
||||
|
||||
span {
|
||||
width: 20%;
|
||||
background-color: #79ffe1;
|
||||
background-color: #50e3c2;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
@@ -219,7 +219,7 @@ initialize {
|
||||
|
||||
span {
|
||||
width: 20%;
|
||||
background-color: #79ffe1;
|
||||
background-color: #50e3c2;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
@@ -386,7 +386,7 @@ initialize {
|
||||
|
||||
span {
|
||||
width: 66.67%;
|
||||
background-color: #c00;
|
||||
background-color: #c50000;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
@@ -429,7 +429,7 @@ initialize {
|
||||
|
||||
span {
|
||||
width: 66.67%;
|
||||
background-color: #c00;
|
||||
background-color: #c50000;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
@@ -633,7 +633,7 @@ initialize {
|
||||
|
||||
span {
|
||||
width: 66.67%;
|
||||
background-color: #c00;
|
||||
background-color: #c50000;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
@@ -676,7 +676,7 @@ initialize {
|
||||
|
||||
span {
|
||||
width: 66.67%;
|
||||
background-color: #c00;
|
||||
background-color: #c50000;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
@@ -752,7 +752,7 @@ initialize {
|
||||
|
||||
span {
|
||||
width: 20%;
|
||||
background-color: #79ffe1;
|
||||
background-color: #50e3c2;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
@@ -795,7 +795,7 @@ initialize {
|
||||
|
||||
span {
|
||||
width: 20%;
|
||||
background-color: #79ffe1;
|
||||
background-color: #50e3c2;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
@@ -880,7 +880,7 @@ initialize {
|
||||
|
||||
span {
|
||||
width: 66.67%;
|
||||
background-color: #c00;
|
||||
background-color: #c50000;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
@@ -923,7 +923,7 @@ initialize {
|
||||
|
||||
span {
|
||||
width: 66.67%;
|
||||
background-color: #c00;
|
||||
background-color: #c50000;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
@@ -1094,7 +1094,7 @@ initialize {
|
||||
|
||||
span {
|
||||
width: 20%;
|
||||
background-color: #79ffe1;
|
||||
background-color: #50e3c2;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
@@ -1137,7 +1137,7 @@ initialize {
|
||||
|
||||
span {
|
||||
width: 20%;
|
||||
background-color: #79ffe1;
|
||||
background-color: #50e3c2;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
@@ -213,7 +213,7 @@ initialize {
|
||||
|
||||
pre code {
|
||||
color: #000;
|
||||
font-size: 0.75rem;
|
||||
font-size: 0.8125rem;
|
||||
line-height: 1.25rem;
|
||||
white-space: pre;
|
||||
}
|
||||
@@ -547,7 +547,7 @@ initialize {
|
||||
|
||||
pre code {
|
||||
color: #fff;
|
||||
font-size: 0.75rem;
|
||||
font-size: 0.8125rem;
|
||||
line-height: 1.25rem;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
@@ -216,7 +216,7 @@ const CssBaseline: React.FC<React.PropsWithChildren<{}>> = ({ children }) => {
|
||||
|
||||
pre code {
|
||||
color: ${theme.palette.foreground};
|
||||
font-size: 0.75rem;
|
||||
font-size: 0.8125rem;
|
||||
line-height: 1.25rem;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
@@ -721,7 +721,7 @@ initialize {
|
||||
width: 0.625rem;
|
||||
height: 0.625rem;
|
||||
border-radius: 50%;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
@@ -787,7 +787,7 @@ initialize {
|
||||
width: 0.625rem;
|
||||
height: 0.625rem;
|
||||
border-radius: 50%;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
@@ -853,7 +853,7 @@ initialize {
|
||||
width: 0.625rem;
|
||||
height: 0.625rem;
|
||||
border-radius: 50%;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
@@ -1443,7 +1443,7 @@ initialize {
|
||||
width: 0.625rem;
|
||||
height: 0.625rem;
|
||||
border-radius: 50%;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
@@ -1509,7 +1509,7 @@ initialize {
|
||||
width: 0.625rem;
|
||||
height: 0.625rem;
|
||||
border-radius: 50%;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
@@ -1575,7 +1575,7 @@ initialize {
|
||||
width: 0.625rem;
|
||||
height: 0.625rem;
|
||||
border-radius: 50%;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
@@ -2165,7 +2165,7 @@ initialize {
|
||||
width: 0.625rem;
|
||||
height: 0.625rem;
|
||||
border-radius: 50%;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
@@ -2231,7 +2231,7 @@ initialize {
|
||||
width: 0.625rem;
|
||||
height: 0.625rem;
|
||||
border-radius: 50%;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
@@ -2297,7 +2297,7 @@ initialize {
|
||||
width: 0.625rem;
|
||||
height: 0.625rem;
|
||||
border-radius: 50%;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
@@ -2887,7 +2887,7 @@ initialize {
|
||||
width: 0.625rem;
|
||||
height: 0.625rem;
|
||||
border-radius: 50%;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
@@ -2953,7 +2953,7 @@ initialize {
|
||||
width: 0.625rem;
|
||||
height: 0.625rem;
|
||||
border-radius: 50%;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
@@ -3019,7 +3019,7 @@ initialize {
|
||||
width: 0.625rem;
|
||||
height: 0.625rem;
|
||||
border-radius: 50%;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ exports[`Grid all breakpoint values should be supported 1`] = `
|
||||
flex-grow: 0;
|
||||
max-width: 4.166666666666667%;
|
||||
flex-basis: 4.166666666666667%;
|
||||
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 650px) {
|
||||
@@ -32,6 +33,7 @@ exports[`Grid all breakpoint values should be supported 1`] = `
|
||||
flex-grow: 0;
|
||||
max-width: 4.166666666666667%;
|
||||
flex-basis: 4.166666666666667%;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +42,7 @@ exports[`Grid all breakpoint values should be supported 1`] = `
|
||||
flex-grow: 0;
|
||||
max-width: 8.333333333333334%;
|
||||
flex-basis: 8.333333333333334%;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +51,7 @@ exports[`Grid all breakpoint values should be supported 1`] = `
|
||||
flex-grow: 0;
|
||||
max-width: 12.5%;
|
||||
flex-basis: 12.5%;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +60,7 @@ exports[`Grid all breakpoint values should be supported 1`] = `
|
||||
flex-grow: 0;
|
||||
max-width: 16.666666666666668%;
|
||||
flex-basis: 16.666666666666668%;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,6 +69,7 @@ exports[`Grid all breakpoint values should be supported 1`] = `
|
||||
flex-grow: 0;
|
||||
max-width: 20.833333333333336%;
|
||||
flex-basis: 20.833333333333336%;
|
||||
|
||||
}
|
||||
}
|
||||
</style></div><style>
|
||||
@@ -90,6 +96,7 @@ exports[`Grid all breakpoint values should be supported 1`] = `
|
||||
flex-grow: 0;
|
||||
max-width: 4.166666666666667%;
|
||||
flex-basis: 4.166666666666667%;
|
||||
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 650px) {
|
||||
@@ -97,6 +104,7 @@ exports[`Grid all breakpoint values should be supported 1`] = `
|
||||
flex-grow: 0;
|
||||
max-width: 4.166666666666667%;
|
||||
flex-basis: 4.166666666666667%;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,6 +113,7 @@ exports[`Grid all breakpoint values should be supported 1`] = `
|
||||
flex-grow: 0;
|
||||
max-width: 8.333333333333334%;
|
||||
flex-basis: 8.333333333333334%;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,6 +122,7 @@ exports[`Grid all breakpoint values should be supported 1`] = `
|
||||
flex-grow: 0;
|
||||
max-width: 12.5%;
|
||||
flex-basis: 12.5%;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,6 +131,7 @@ exports[`Grid all breakpoint values should be supported 1`] = `
|
||||
flex-grow: 0;
|
||||
max-width: 16.666666666666668%;
|
||||
flex-basis: 16.666666666666668%;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,6 +140,7 @@ exports[`Grid all breakpoint values should be supported 1`] = `
|
||||
flex-grow: 0;
|
||||
max-width: 20.833333333333336%;
|
||||
flex-basis: 20.833333333333336%;
|
||||
|
||||
}
|
||||
}
|
||||
</style></div>"
|
||||
@@ -159,6 +171,7 @@ exports[`Grid css value should be passed through 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 650px) {
|
||||
@@ -166,6 +179,7 @@ exports[`Grid css value should be passed through 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,6 +188,7 @@ exports[`Grid css value should be passed through 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,6 +197,7 @@ exports[`Grid css value should be passed through 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,6 +206,7 @@ exports[`Grid css value should be passed through 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,6 +215,7 @@ exports[`Grid css value should be passed through 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
</style></div><style>
|
||||
@@ -224,6 +242,7 @@ exports[`Grid css value should be passed through 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 650px) {
|
||||
@@ -231,6 +250,7 @@ exports[`Grid css value should be passed through 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,6 +259,7 @@ exports[`Grid css value should be passed through 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,6 +268,7 @@ exports[`Grid css value should be passed through 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -255,6 +277,7 @@ exports[`Grid css value should be passed through 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,6 +286,7 @@ exports[`Grid css value should be passed through 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
</style></div>"
|
||||
@@ -293,6 +317,7 @@ exports[`Grid decimal spacing should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 650px) {
|
||||
@@ -300,6 +325,7 @@ exports[`Grid decimal spacing should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,6 +334,7 @@ exports[`Grid decimal spacing should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,6 +343,7 @@ exports[`Grid decimal spacing should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,6 +352,7 @@ exports[`Grid decimal spacing should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -332,6 +361,7 @@ exports[`Grid decimal spacing should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
</style></div><style>
|
||||
@@ -358,6 +388,7 @@ exports[`Grid decimal spacing should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 650px) {
|
||||
@@ -365,6 +396,7 @@ exports[`Grid decimal spacing should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -373,6 +405,7 @@ exports[`Grid decimal spacing should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,6 +414,7 @@ exports[`Grid decimal spacing should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -389,6 +423,7 @@ exports[`Grid decimal spacing should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -397,6 +432,7 @@ exports[`Grid decimal spacing should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
</style></div>"
|
||||
@@ -427,6 +463,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 650px) {
|
||||
@@ -434,6 +471,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -442,6 +480,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -450,6 +489,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -458,6 +498,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -466,6 +507,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
</style></div><div class=\\"item mock \\"><div class=\\"item mock \\">test<style>
|
||||
@@ -492,6 +534,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 650px) {
|
||||
@@ -499,6 +542,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -507,6 +551,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -515,6 +560,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -523,6 +569,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -531,6 +578,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
</style></div><div class=\\"item mock \\"><div class=\\"item mock \\">test<style>
|
||||
@@ -557,6 +605,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 650px) {
|
||||
@@ -564,6 +613,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -572,6 +622,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -580,6 +631,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -588,6 +640,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -596,6 +649,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
</style></div><div class=\\"item mock \\"><div class=\\"item mock \\">test<style>
|
||||
@@ -622,6 +676,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 650px) {
|
||||
@@ -629,6 +684,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -637,6 +693,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -645,6 +702,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -653,6 +711,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -661,6 +720,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
</style></div><style>
|
||||
@@ -687,6 +747,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 650px) {
|
||||
@@ -694,6 +755,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -702,6 +764,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -710,6 +773,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -718,6 +782,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -726,6 +791,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
</style></div>,<style>
|
||||
@@ -752,6 +818,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 650px) {
|
||||
@@ -759,6 +826,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -767,6 +835,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -775,6 +844,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -783,6 +853,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -791,6 +862,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
</style></div>,<style>
|
||||
@@ -817,6 +889,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 650px) {
|
||||
@@ -824,6 +897,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -832,6 +906,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -840,6 +915,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -848,6 +924,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -856,6 +933,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
</style></div>,<style>
|
||||
@@ -882,6 +960,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 650px) {
|
||||
@@ -889,6 +968,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -897,6 +977,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -905,6 +986,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -913,6 +995,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -921,6 +1004,7 @@ exports[`Grid nested components should be supported 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
</style></div>"
|
||||
@@ -951,6 +1035,7 @@ exports[`Grid should render correctly 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 650px) {
|
||||
@@ -958,6 +1043,7 @@ exports[`Grid should render correctly 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -966,6 +1052,7 @@ exports[`Grid should render correctly 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -974,6 +1061,7 @@ exports[`Grid should render correctly 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -982,6 +1070,7 @@ exports[`Grid should render correctly 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -990,6 +1079,7 @@ exports[`Grid should render correctly 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
</style></div><div class=\\"item mock \\">test<style>
|
||||
@@ -1016,6 +1106,7 @@ exports[`Grid should render correctly 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 650px) {
|
||||
@@ -1023,6 +1114,7 @@ exports[`Grid should render correctly 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1031,6 +1123,7 @@ exports[`Grid should render correctly 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1039,6 +1132,7 @@ exports[`Grid should render correctly 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1047,6 +1141,7 @@ exports[`Grid should render correctly 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1055,6 +1150,7 @@ exports[`Grid should render correctly 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
</style></div><style>
|
||||
@@ -1081,6 +1177,7 @@ exports[`Grid should render correctly 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 650px) {
|
||||
@@ -1088,6 +1185,7 @@ exports[`Grid should render correctly 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1096,6 +1194,7 @@ exports[`Grid should render correctly 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1104,6 +1203,7 @@ exports[`Grid should render correctly 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1112,6 +1212,7 @@ exports[`Grid should render correctly 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1120,6 +1221,7 @@ exports[`Grid should render correctly 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
</style></div>"
|
||||
@@ -1150,6 +1252,7 @@ exports[`Grid should work correctly when size exceeds 1`] = `
|
||||
flex-grow: 0;
|
||||
max-width: 100%;
|
||||
flex-basis: 100%;
|
||||
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 650px) {
|
||||
@@ -1157,6 +1260,7 @@ exports[`Grid should work correctly when size exceeds 1`] = `
|
||||
flex-grow: 0;
|
||||
max-width: 100%;
|
||||
flex-basis: 100%;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1165,6 +1269,7 @@ exports[`Grid should work correctly when size exceeds 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1173,6 +1278,7 @@ exports[`Grid should work correctly when size exceeds 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1181,6 +1287,7 @@ exports[`Grid should work correctly when size exceeds 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1189,6 +1296,7 @@ exports[`Grid should work correctly when size exceeds 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
</style></div><div class=\\"item xs mock \\">test<style>
|
||||
@@ -1215,6 +1323,7 @@ exports[`Grid should work correctly when size exceeds 1`] = `
|
||||
flex-grow: 0;
|
||||
max-width: 0;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 650px) {
|
||||
@@ -1222,6 +1331,7 @@ exports[`Grid should work correctly when size exceeds 1`] = `
|
||||
flex-grow: 0;
|
||||
max-width: 0;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1230,6 +1340,7 @@ exports[`Grid should work correctly when size exceeds 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1238,6 +1349,7 @@ exports[`Grid should work correctly when size exceeds 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1246,6 +1358,7 @@ exports[`Grid should work correctly when size exceeds 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1254,6 +1367,7 @@ exports[`Grid should work correctly when size exceeds 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
</style></div><style>
|
||||
@@ -1280,6 +1394,7 @@ exports[`Grid should work correctly when size exceeds 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 650px) {
|
||||
@@ -1287,6 +1402,7 @@ exports[`Grid should work correctly when size exceeds 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1295,6 +1411,7 @@ exports[`Grid should work correctly when size exceeds 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1303,6 +1420,7 @@ exports[`Grid should work correctly when size exceeds 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1311,6 +1429,7 @@ exports[`Grid should work correctly when size exceeds 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1319,6 +1438,7 @@ exports[`Grid should work correctly when size exceeds 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
</style></div>"
|
||||
|
||||
@@ -111,4 +111,10 @@ describe('Grid', () => {
|
||||
expect(wrapper.html()).toMatchSnapshot()
|
||||
expect(() => wrapper.unmount()).not.toThrow()
|
||||
})
|
||||
|
||||
it('Grid should be hidden when value is 0', () => {
|
||||
let wrapper = mount(<Grid.Container xs={0} />)
|
||||
expect(wrapper.find('.item').hasClass('xs')).toBeTruthy()
|
||||
expect(wrapper.find('.item').html()).toContain('display: none')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -32,19 +32,23 @@ type ItemLayoutValue = {
|
||||
grow: number
|
||||
width: string
|
||||
basis: string
|
||||
display: string
|
||||
}
|
||||
const getItemLayout = (val: BreakpointsValue): ItemLayoutValue => {
|
||||
const display = val === 0 ? 'display: none;' : ''
|
||||
if (typeof val === 'number') {
|
||||
const width = (100 / 24) * val
|
||||
const ratio = width > 100 ? '100%' : width < 0 ? '0' : `${width}%`
|
||||
return {
|
||||
grow: 0,
|
||||
display,
|
||||
width: ratio,
|
||||
basis: ratio,
|
||||
}
|
||||
}
|
||||
return {
|
||||
grow: 1,
|
||||
display,
|
||||
width: '100%',
|
||||
basis: '0',
|
||||
}
|
||||
@@ -62,6 +66,7 @@ const GridBasicItem: React.FC<React.PropsWithChildren<GridBasicItemProps>> = ({
|
||||
alignContent,
|
||||
children,
|
||||
className,
|
||||
...props
|
||||
}) => {
|
||||
const theme = useTheme()
|
||||
const classes = useMemo(() => {
|
||||
@@ -77,11 +82,11 @@ const GridBasicItem: React.FC<React.PropsWithChildren<GridBasicItemProps>> = ({
|
||||
xl,
|
||||
}
|
||||
const classString = Object.keys(aligns).reduce((pre, name) => {
|
||||
if (Boolean(aligns[name]) && aligns[name] !== 0) return `${pre} ${name}`
|
||||
if (aligns[name] !== undefined && aligns[name] !== false) return `${pre} ${name}`
|
||||
return pre
|
||||
}, '')
|
||||
return classString.trim()
|
||||
}, [justify, direction, alignItems, alignContent])
|
||||
}, [justify, direction, alignItems, alignContent, xs, sm, md, lg, xl])
|
||||
|
||||
const layout = useMemo<
|
||||
{
|
||||
@@ -99,7 +104,7 @@ const GridBasicItem: React.FC<React.PropsWithChildren<GridBasicItemProps>> = ({
|
||||
)
|
||||
|
||||
return (
|
||||
<div className={`item ${classes} ${className}`}>
|
||||
<div className={`item ${classes} ${className}`} {...props}>
|
||||
{children}
|
||||
<style jsx>{`
|
||||
.item {
|
||||
@@ -125,6 +130,7 @@ const GridBasicItem: React.FC<React.PropsWithChildren<GridBasicItemProps>> = ({
|
||||
flex-grow: ${layout.xs.grow};
|
||||
max-width: ${layout.xs.width};
|
||||
flex-basis: ${layout.xs.basis};
|
||||
${layout.xs.display}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: ${theme.breakpoints.xs.max}) {
|
||||
@@ -132,6 +138,7 @@ const GridBasicItem: React.FC<React.PropsWithChildren<GridBasicItemProps>> = ({
|
||||
flex-grow: ${layout.xs.grow};
|
||||
max-width: ${layout.xs.width};
|
||||
flex-basis: ${layout.xs.basis};
|
||||
${layout.xs.display}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,6 +147,7 @@ const GridBasicItem: React.FC<React.PropsWithChildren<GridBasicItemProps>> = ({
|
||||
flex-grow: ${layout.sm.grow};
|
||||
max-width: ${layout.sm.width};
|
||||
flex-basis: ${layout.sm.basis};
|
||||
${layout.sm.display}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,6 +156,7 @@ const GridBasicItem: React.FC<React.PropsWithChildren<GridBasicItemProps>> = ({
|
||||
flex-grow: ${layout.md.grow};
|
||||
max-width: ${layout.md.width};
|
||||
flex-basis: ${layout.md.basis};
|
||||
${layout.md.display}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,6 +165,7 @@ const GridBasicItem: React.FC<React.PropsWithChildren<GridBasicItemProps>> = ({
|
||||
flex-grow: ${layout.lg.grow};
|
||||
max-width: ${layout.lg.width};
|
||||
flex-basis: ${layout.lg.basis};
|
||||
${layout.lg.display}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,6 +174,7 @@ const GridBasicItem: React.FC<React.PropsWithChildren<GridBasicItemProps>> = ({
|
||||
flex-grow: ${layout.xl.grow};
|
||||
max-width: ${layout.xl.width};
|
||||
flex-basis: ${layout.xl.basis};
|
||||
${layout.xl.display}
|
||||
}
|
||||
}
|
||||
`}</style>
|
||||
|
||||
@@ -59,4 +59,15 @@ describe('Image Browser', () => {
|
||||
const wrapper = mount(<Image.Browser />)
|
||||
expect(() => wrapper.unmount()).not.toThrow()
|
||||
})
|
||||
|
||||
it('anchor props should be passed through', () => {
|
||||
const anchorRel = 'noreferrer'
|
||||
const wrapper = mount(
|
||||
<Image.Browser url={link} anchorProps={{ rel: anchorRel }}>
|
||||
<Image src={url} />
|
||||
</Image.Browser>,
|
||||
)
|
||||
const rel = wrapper.find('a').getDOMNode().getAttribute('rel')
|
||||
expect(anchorRel).toEqual(anchorRel)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,21 +1,26 @@
|
||||
import React, { useMemo } from 'react'
|
||||
import Link from '../link'
|
||||
import { Props as LinkProps } from '../link/link'
|
||||
import useTheme from '../styles/use-theme'
|
||||
import withDefaults from '../utils/with-defaults'
|
||||
import ImageBrowserHttpsIcon from './image-browser-https-icon'
|
||||
import { getBrowserColors, BrowserColors } from './styles'
|
||||
|
||||
type AnchorProps = Omit<React.AnchorHTMLAttributes<any>, keyof LinkProps>
|
||||
|
||||
interface Props {
|
||||
title?: string
|
||||
url?: string
|
||||
showFullLink?: boolean
|
||||
invert?: boolean
|
||||
anchorProps?: AnchorProps
|
||||
className?: string
|
||||
}
|
||||
|
||||
const defaultProps = {
|
||||
className: '',
|
||||
showFullLink: false,
|
||||
anchorProps: {} as AnchorProps,
|
||||
invert: false,
|
||||
}
|
||||
|
||||
@@ -42,12 +47,17 @@ const getTitle = (title: string, colors: BrowserColors) => (
|
||||
</div>
|
||||
)
|
||||
|
||||
const getAddressInput = (url: string, showFullLink: boolean, colors: BrowserColors) => (
|
||||
const getAddressInput = (
|
||||
url: string,
|
||||
showFullLink: boolean,
|
||||
colors: BrowserColors,
|
||||
anchorProps: AnchorProps,
|
||||
) => (
|
||||
<div className="address-input">
|
||||
<span className="https">
|
||||
<ImageBrowserHttpsIcon />
|
||||
</span>
|
||||
<Link href={url} title={url} target="_blank">
|
||||
<Link href={url} title={url} target="_blank" {...anchorProps}>
|
||||
{showFullLink ? url : getHostFromUrl(url)}
|
||||
</Link>
|
||||
<style jsx>{`
|
||||
@@ -94,16 +104,16 @@ const getAddressInput = (url: string, showFullLink: boolean, colors: BrowserColo
|
||||
|
||||
const ImageBrowser = React.forwardRef<HTMLDivElement, React.PropsWithChildren<ImageBrowserProps>>(
|
||||
(
|
||||
{ url, title, children, showFullLink, invert, className, ...props },
|
||||
{ url, title, children, showFullLink, invert, anchorProps, className, ...props },
|
||||
ref: React.Ref<HTMLDivElement>,
|
||||
) => {
|
||||
const theme = useTheme()
|
||||
const colors = useMemo(() => getBrowserColors(invert, theme.palette), [invert, theme.palette])
|
||||
const input = useMemo(() => {
|
||||
if (url) return getAddressInput(url, showFullLink, colors)
|
||||
if (url) return getAddressInput(url, showFullLink, colors, anchorProps)
|
||||
if (title) return getTitle(title, colors)
|
||||
return null
|
||||
}, [url, showFullLink, title, colors])
|
||||
}, [url, showFullLink, title, colors, anchorProps])
|
||||
|
||||
return (
|
||||
<div className={`bowser ${className}`} ref={ref} {...props}>
|
||||
|
||||
@@ -58,3 +58,5 @@ export { default as User } from './user'
|
||||
export { default as Page } from './page'
|
||||
export { default as Grid } from './grid'
|
||||
export { default as ButtonGroup } from './button-group'
|
||||
export { default as Breadcrumbs } from './breadcrumbs'
|
||||
export { default as Pagination } from './pagination'
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import React, { Dispatch, MutableRefObject, SetStateAction } from 'react'
|
||||
import useCurrentState from '../utils/use-current-state'
|
||||
|
||||
export type BindingsChangeTarget =
|
||||
| React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>
|
||||
| string
|
||||
|
||||
const useInput = (
|
||||
initialValue: string,
|
||||
): {
|
||||
@@ -10,7 +14,7 @@ const useInput = (
|
||||
reset: () => void
|
||||
bindings: {
|
||||
value: string
|
||||
onChange: (event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => void
|
||||
onChange: (event: BindingsChangeTarget) => void
|
||||
}
|
||||
} => {
|
||||
const [state, setState, currentRef] = useCurrentState<string>(initialValue)
|
||||
@@ -22,8 +26,12 @@ const useInput = (
|
||||
reset: () => setState(initialValue),
|
||||
bindings: {
|
||||
value: state,
|
||||
onChange: (event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
||||
setState(event.target.value)
|
||||
onChange: (event: BindingsChangeTarget) => {
|
||||
if (typeof event === 'object' && event.target) {
|
||||
setState(event.target.value)
|
||||
} else {
|
||||
setState(event as string)
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import useTheme from '../styles/use-theme'
|
||||
import useWarning from '../utils/use-warning'
|
||||
import LinkIcon from './icon'
|
||||
|
||||
interface Props {
|
||||
export interface Props {
|
||||
href?: string
|
||||
color?: boolean
|
||||
pure?: boolean
|
||||
|
||||
@@ -760,7 +760,7 @@ exports[`Loading should work with different types 1`] = `
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
border-radius: 50%;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
margin: 0 1px;
|
||||
display: inline-block;
|
||||
animation: loading-blink 1.4s infinite both;
|
||||
|
||||
@@ -9,6 +9,7 @@ exports[`Modal customization should be supported 1`] = `
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
display: inline-flex;
|
||||
flex-shrink: 0;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
word-break: break-word;
|
||||
@@ -18,6 +19,7 @@ exports[`Modal customization should be supported 1`] = `
|
||||
</style><style>
|
||||
.wrapper {
|
||||
max-width: 85vw;
|
||||
max-height: 75vh;
|
||||
width: 100px;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
@@ -66,6 +68,7 @@ exports[`Modal should render correctly 1`] = `
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
display: inline-flex;
|
||||
flex-shrink: 0;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
word-break: break-word;
|
||||
@@ -88,8 +91,9 @@ exports[`Modal should render correctly 1`] = `
|
||||
}
|
||||
</style><div class=\\"content \\"><p>Some content contained within the modal.</p></div><style>
|
||||
.content {
|
||||
margin: 0;
|
||||
padding: 16pt 0 8pt 0;
|
||||
margin: 0 -16pt;
|
||||
padding: 16pt 16pt 8pt;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.content > :global(*:first-child) {
|
||||
@@ -166,10 +170,12 @@ exports[`Modal should render correctly 1`] = `
|
||||
|
||||
div {
|
||||
height: 3.625rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
</style><style>
|
||||
.wrapper {
|
||||
max-width: 85vw;
|
||||
max-height: 75vh;
|
||||
width: 26rem;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
@@ -215,7 +221,7 @@ exports[`Modal should render correctly 1`] = `
|
||||
align-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
justify-content: space-around;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
overflow: auto;
|
||||
@@ -232,8 +238,9 @@ exports[`Modal should render correctly 1`] = `
|
||||
}
|
||||
|
||||
.offset {
|
||||
height: 25vh;
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
display: flex;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ const ModalActions: React.FC<React.PropsWithChildren<{}>> = ({ children, ...prop
|
||||
|
||||
div {
|
||||
height: 3.625rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
`}</style>
|
||||
</>
|
||||
|
||||
@@ -23,8 +23,9 @@ const ModalContent: React.FC<ModalContentProps> = ({ className, children, ...pro
|
||||
</div>
|
||||
<style jsx>{`
|
||||
.content {
|
||||
margin: 0;
|
||||
padding: ${theme.layout.gap} 0 ${theme.layout.gapHalf} 0;
|
||||
margin: 0 -${theme.layout.gap};
|
||||
padding: ${theme.layout.gap} ${theme.layout.gap} ${theme.layout.gapHalf};
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.content > :global(*:first-child) {
|
||||
|
||||
@@ -29,6 +29,7 @@ const ModalTitle: React.FC<ModalTitleProps> = ({ className, children, ...props }
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
display: inline-flex;
|
||||
flex-shrink: 0;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
word-break: break-word;
|
||||
|
||||
@@ -32,6 +32,7 @@ const ModalWrapper: React.FC<React.PropsWithChildren<ModalWrapperProps>> = ({
|
||||
<style jsx>{`
|
||||
.wrapper {
|
||||
max-width: 85vw;
|
||||
max-height: 75vh;
|
||||
width: ${width};
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
|
||||
@@ -80,7 +80,7 @@ const Modal: React.FC<React.PropsWithChildren<ModalProps>> = ({
|
||||
if (!portal) return null
|
||||
return createPortal(
|
||||
<ModalContext.Provider value={modalConfig}>
|
||||
<Backdrop onClick={closeFromBackdrop} visible={visible} offsetY={25}>
|
||||
<Backdrop onClick={closeFromBackdrop} visible={visible}>
|
||||
<ModalWrapper visible={visible} className={wrapClassName} width={wrapperWidth}>
|
||||
{withoutActionsChildren}
|
||||
{hasActions && <ModalActions>{ActionsChildren}</ModalActions>}
|
||||
|
||||
@@ -182,8 +182,8 @@ exports[`Note should work with different types 1`] = `
|
||||
padding: 8pt 16pt;
|
||||
font-size: 14px;
|
||||
line-height: 1.8;
|
||||
border: 1px solid #ff0000;
|
||||
color: #ff0000;
|
||||
border: 1px solid #e00;
|
||||
color: #e00;
|
||||
background-color: #fff;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Pagination should render correctly 1`] = `
|
||||
"<nav><li><button class=\\" disabled\\">prev</button><style>
|
||||
li {
|
||||
margin-right: 6px;
|
||||
display: inline-block;
|
||||
}
|
||||
button {
|
||||
border: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
text-transform: capitalize;
|
||||
user-select: none;
|
||||
white-space: nowrap;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
box-shadow: none;
|
||||
outline: none;
|
||||
height: var(--pagination-size);
|
||||
min-width: var(--pagination-size);
|
||||
font-size: inherit;
|
||||
cursor: pointer;
|
||||
color: #0070f3;
|
||||
border-radius: 5px;
|
||||
background-color: #fff;
|
||||
transition: all linear 200ms 0ms;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: rgba(0, 112, 243, 0.1);
|
||||
}
|
||||
|
||||
.active {
|
||||
font-weight: bold;
|
||||
background-color: #0070f3;
|
||||
color: #fff;
|
||||
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.active:hover {
|
||||
background-color: rgba(0, 112, 243, 0.8);
|
||||
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.disabled {
|
||||
color: #888;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.disabled:hover {
|
||||
background-color: #eaeaea;
|
||||
}
|
||||
|
||||
button :global(svg) {
|
||||
width: 1.3em;
|
||||
height: 1.3em;
|
||||
}
|
||||
</style></li><li><button class=\\"active \\">1</button><style>
|
||||
li {
|
||||
margin-right: 6px;
|
||||
display: inline-block;
|
||||
}
|
||||
button {
|
||||
border: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
text-transform: capitalize;
|
||||
user-select: none;
|
||||
white-space: nowrap;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
box-shadow: none;
|
||||
outline: none;
|
||||
height: var(--pagination-size);
|
||||
min-width: var(--pagination-size);
|
||||
font-size: inherit;
|
||||
cursor: pointer;
|
||||
color: #0070f3;
|
||||
border-radius: 5px;
|
||||
background-color: #fff;
|
||||
transition: all linear 200ms 0ms;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: rgba(0, 112, 243, 0.1);
|
||||
}
|
||||
|
||||
.active {
|
||||
font-weight: bold;
|
||||
background-color: #0070f3;
|
||||
color: #fff;
|
||||
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.active:hover {
|
||||
background-color: rgba(0, 112, 243, 0.8);
|
||||
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.disabled {
|
||||
color: #888;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.disabled:hover {
|
||||
background-color: #eaeaea;
|
||||
}
|
||||
|
||||
button :global(svg) {
|
||||
width: 1.3em;
|
||||
height: 1.3em;
|
||||
}
|
||||
</style></li><li><button class=\\" disabled\\">next</button><style>
|
||||
li {
|
||||
margin-right: 6px;
|
||||
display: inline-block;
|
||||
}
|
||||
button {
|
||||
border: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
text-transform: capitalize;
|
||||
user-select: none;
|
||||
white-space: nowrap;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
box-shadow: none;
|
||||
outline: none;
|
||||
height: var(--pagination-size);
|
||||
min-width: var(--pagination-size);
|
||||
font-size: inherit;
|
||||
cursor: pointer;
|
||||
color: #0070f3;
|
||||
border-radius: 5px;
|
||||
background-color: #fff;
|
||||
transition: all linear 200ms 0ms;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: rgba(0, 112, 243, 0.1);
|
||||
}
|
||||
|
||||
.active {
|
||||
font-weight: bold;
|
||||
background-color: #0070f3;
|
||||
color: #fff;
|
||||
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.active:hover {
|
||||
background-color: rgba(0, 112, 243, 0.8);
|
||||
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.disabled {
|
||||
color: #888;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.disabled:hover {
|
||||
background-color: #eaeaea;
|
||||
}
|
||||
|
||||
button :global(svg) {
|
||||
width: 1.3em;
|
||||
height: 1.3em;
|
||||
}
|
||||
</style></li></nav><style>
|
||||
nav {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-variant: tabular-nums;
|
||||
font-feature-settings: 'tnum';
|
||||
font-size: .875rem;
|
||||
--pagination-size: 2rem;
|
||||
}
|
||||
|
||||
nav :global(button:last-of-type) {
|
||||
margin-right: 0;
|
||||
}
|
||||
</style>"
|
||||
`;
|
||||
148
components/pagination/__tests__/pagination.test.tsx
Normal file
148
components/pagination/__tests__/pagination.test.tsx
Normal file
@@ -0,0 +1,148 @@
|
||||
import React from 'react'
|
||||
import { mount } from 'enzyme'
|
||||
import { Pagination } from 'components'
|
||||
import { act } from 'react-dom/test-utils'
|
||||
import { updateWrapper } from 'tests/utils'
|
||||
|
||||
describe('Pagination', () => {
|
||||
it('should render correctly', () => {
|
||||
const wrapper = mount(<Pagination />)
|
||||
expect(wrapper.html()).toMatchSnapshot()
|
||||
expect(() => wrapper.unmount()).not.toThrow()
|
||||
})
|
||||
|
||||
it('the specified page should be activated', async () => {
|
||||
const wrapper = mount(<Pagination count={10} initialPage={2} />)
|
||||
expect(wrapper.find('.active').text()).toEqual('2')
|
||||
await act(async () => {
|
||||
wrapper.setProps({ page: 10 })
|
||||
})
|
||||
await updateWrapper(wrapper, 200)
|
||||
expect(wrapper.find('.active').text()).toEqual('10')
|
||||
})
|
||||
|
||||
it('should trigger change event', async () => {
|
||||
let current = 1
|
||||
const handler = jest.fn().mockImplementation(val => (current = val))
|
||||
const wrapper = mount(<Pagination count={10} initialPage={2} onChange={handler} />)
|
||||
|
||||
await act(async () => {
|
||||
wrapper.setProps({ page: 10 })
|
||||
})
|
||||
await updateWrapper(wrapper, 200)
|
||||
expect(handler).toHaveBeenCalled()
|
||||
expect(current).toEqual(10)
|
||||
|
||||
const btns = wrapper.find('button')
|
||||
btns.at(0).simulate('click')
|
||||
await updateWrapper(wrapper, 200)
|
||||
expect(current).toEqual(9)
|
||||
|
||||
btns.at(btns.length - 1).simulate('click')
|
||||
btns.at(btns.length - 1).simulate('click')
|
||||
btns.at(btns.length - 1).simulate('click')
|
||||
btns.at(btns.length - 1).simulate('click')
|
||||
await updateWrapper(wrapper, 200)
|
||||
expect(current).toEqual(10)
|
||||
handler.mockRestore()
|
||||
})
|
||||
|
||||
it('the page should be rendered to follow the specified limit', async () => {
|
||||
const wrapper = mount(<Pagination count={20} limit={20} />)
|
||||
expect(wrapper.find('button').length).toBeGreaterThanOrEqual(20)
|
||||
await act(async () => {
|
||||
wrapper.setProps({ limit: 5 })
|
||||
})
|
||||
await updateWrapper(wrapper, 200)
|
||||
expect(wrapper.find('button').length).toBeLessThanOrEqual(10)
|
||||
})
|
||||
|
||||
it('should be render all pages when limit is greater than the total', async () => {
|
||||
const handler = jest.fn()
|
||||
const wrapper = mount(<Pagination count={15} limit={40} onChange={handler} />)
|
||||
expect(wrapper.find('button').length).toBeGreaterThanOrEqual(15)
|
||||
wrapper.find('button').at(10).simulate('click')
|
||||
await updateWrapper(wrapper, 200)
|
||||
|
||||
expect(handler).toHaveBeenCalled()
|
||||
handler.mockRestore()
|
||||
})
|
||||
|
||||
it('omit pages by limit value', async () => {
|
||||
const wrapper = mount(<Pagination count={20} limit={5} />)
|
||||
const btn4 = wrapper.find('button').at(4)
|
||||
expect(btn4.text()).toEqual('4')
|
||||
btn4.simulate('click')
|
||||
await updateWrapper(wrapper, 200)
|
||||
let btns = wrapper.find('button').map(btn => btn.text())
|
||||
expect(btns.includes('2')).not.toBeTruthy()
|
||||
expect(btns.includes('1')).toBeTruthy()
|
||||
expect(btns.includes('3')).toBeTruthy()
|
||||
expect(btns.includes('4')).toBeTruthy()
|
||||
expect(btns.includes('5')).toBeTruthy()
|
||||
expect(btns.includes('6')).not.toBeTruthy()
|
||||
expect(btns.includes('20')).toBeTruthy()
|
||||
|
||||
const btn5 = wrapper.find('button').at(5)
|
||||
expect(btn5.text()).toEqual('5')
|
||||
btn5.simulate('click')
|
||||
await updateWrapper(wrapper, 200)
|
||||
btns = wrapper.find('button').map(btn => btn.text())
|
||||
expect(btns.includes('1')).toBeTruthy()
|
||||
expect(btns.includes('2')).not.toBeTruthy()
|
||||
expect(btns.includes('3')).not.toBeTruthy()
|
||||
expect(btns.includes('4')).toBeTruthy()
|
||||
expect(btns.includes('5')).toBeTruthy()
|
||||
expect(btns.includes('6')).toBeTruthy()
|
||||
expect(btns.includes('7')).not.toBeTruthy()
|
||||
expect(btns.includes('8')).not.toBeTruthy()
|
||||
expect(btns.includes('20')).toBeTruthy()
|
||||
})
|
||||
|
||||
it('should trigger change event when ellipsis clicked', async () => {
|
||||
let current = 20
|
||||
const handler = jest.fn().mockImplementation(val => (current = val))
|
||||
const wrapper = mount(<Pagination count={20} initialPage={20} onChange={handler} />)
|
||||
const btn = wrapper.find('svg').at(0).parents('button')
|
||||
btn.at(0).simulate('click')
|
||||
await updateWrapper(wrapper, 200)
|
||||
expect(handler).toHaveBeenCalled()
|
||||
expect(current).toEqual(15)
|
||||
|
||||
await act(async () => {
|
||||
wrapper.setProps({ page: 1 })
|
||||
})
|
||||
await updateWrapper(wrapper, 200)
|
||||
const lastBtn = wrapper.find('svg').at(0).parents('button')
|
||||
lastBtn.at(0).simulate('click')
|
||||
await updateWrapper(wrapper, 200)
|
||||
expect(current).toEqual(1 + 5)
|
||||
})
|
||||
|
||||
it('another SVG should be displayed when the mouse is moved in', async () => {
|
||||
const wrapper = mount(<Pagination count={20} initialPage={20} />)
|
||||
const svg = wrapper.find('svg').at(0)
|
||||
const btn = svg.parents('button')
|
||||
|
||||
const html = svg.html()
|
||||
btn.simulate('mouseEnter')
|
||||
await updateWrapper(wrapper)
|
||||
expect(html).not.toEqual(wrapper.find('svg').at(0).html())
|
||||
|
||||
btn.simulate('mouseLeave')
|
||||
await updateWrapper(wrapper)
|
||||
expect(html).toEqual(wrapper.find('svg').at(0).html())
|
||||
})
|
||||
|
||||
it('custom buttons should be display', () => {
|
||||
const wrapper = mount(
|
||||
<Pagination count={20}>
|
||||
<Pagination.Previous>custom-prev</Pagination.Previous>
|
||||
<Pagination.Next>custom-next</Pagination.Next>
|
||||
</Pagination>,
|
||||
)
|
||||
const btns = wrapper.find('button')
|
||||
expect(btns.at(0).text()).toEqual('custom-prev')
|
||||
expect(btns.at(btns.length - 1).text()).toEqual('custom-next')
|
||||
})
|
||||
})
|
||||
8
components/pagination/index.ts
Normal file
8
components/pagination/index.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import Pagination from './pagination'
|
||||
import PaginationPrevious from './pagination-previous'
|
||||
import PaginationNext from './pagination-next'
|
||||
|
||||
Pagination.Previous = PaginationPrevious
|
||||
Pagination.Next = PaginationNext
|
||||
|
||||
export default Pagination
|
||||
18
components/pagination/pagination-context.ts
Normal file
18
components/pagination/pagination-context.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import React from 'react'
|
||||
import { tuple } from '../utils/prop-types'
|
||||
const paginationUpdateTypes = tuple('prev', 'next', 'click')
|
||||
|
||||
export type PaginationUpdateType = typeof paginationUpdateTypes[number]
|
||||
|
||||
export interface PaginationConfig {
|
||||
isFirst?: boolean
|
||||
isLast?: boolean
|
||||
update?: (type: PaginationUpdateType) => void
|
||||
}
|
||||
|
||||
const defaultContext = {}
|
||||
|
||||
export const PaginationContext = React.createContext<PaginationConfig>(defaultContext)
|
||||
|
||||
export const usePaginationContext = (): PaginationConfig =>
|
||||
React.useContext<PaginationConfig>(PaginationContext)
|
||||
60
components/pagination/pagination-ellipsis.tsx
Normal file
60
components/pagination/pagination-ellipsis.tsx
Normal file
@@ -0,0 +1,60 @@
|
||||
import React, { useState } from 'react'
|
||||
import PaginationItem from './pagination-item'
|
||||
|
||||
interface Props {
|
||||
isBefore?: boolean
|
||||
onClick?: (e: React.MouseEvent) => void
|
||||
}
|
||||
|
||||
const PaginationEllipsis: React.FC<Props> = ({ isBefore, onClick }) => {
|
||||
const [showMore, setShowMore] = useState(false)
|
||||
|
||||
return (
|
||||
<PaginationItem
|
||||
onClick={e => onClick && onClick(e)}
|
||||
onMouseEnter={() => setShowMore(true)}
|
||||
onMouseLeave={() => setShowMore(false)}>
|
||||
{showMore ? (
|
||||
<svg
|
||||
className="more"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
shapeRendering="geometricPrecision">
|
||||
<path d="M13 17l5-5-5-5" />
|
||||
<path d="M6 17l5-5-5-5" />
|
||||
</svg>
|
||||
) : (
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
shapeRendering="geometricPrecision">
|
||||
<circle cx="12" cy="12" r="1" fill="currentColor" />
|
||||
<circle cx="19" cy="12" r="1" fill="currentColor" />
|
||||
<circle cx="5" cy="12" r="1" fill="currentColor" />
|
||||
</svg>
|
||||
)}
|
||||
|
||||
<style jsx>{`
|
||||
svg {
|
||||
color: currentColor;
|
||||
stroke: currentColor;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
}
|
||||
|
||||
.more {
|
||||
transform: rotate(${isBefore ? '180deg' : '0deg'});
|
||||
}
|
||||
`}</style>
|
||||
</PaginationItem>
|
||||
)
|
||||
}
|
||||
|
||||
export default PaginationEllipsis
|
||||
101
components/pagination/pagination-item.tsx
Normal file
101
components/pagination/pagination-item.tsx
Normal file
@@ -0,0 +1,101 @@
|
||||
import React, { useMemo } from 'react'
|
||||
import useTheme from '../styles/use-theme'
|
||||
import { addColorAlpha } from '../utils/color'
|
||||
|
||||
interface Props {
|
||||
active?: boolean
|
||||
disabled?: boolean
|
||||
onClick?: (e: React.MouseEvent) => void
|
||||
}
|
||||
|
||||
type NativeAttrs = Omit<React.ButtonHTMLAttributes<any>, keyof Props>
|
||||
export type PaginationItemProps = Props & NativeAttrs
|
||||
|
||||
const PaginationItem: React.FC<React.PropsWithChildren<PaginationItemProps>> = ({
|
||||
active,
|
||||
children,
|
||||
disabled,
|
||||
onClick,
|
||||
...props
|
||||
}) => {
|
||||
const theme = useTheme()
|
||||
const [hover, activeHover] = useMemo(
|
||||
() => [addColorAlpha(theme.palette.success, 0.1), addColorAlpha(theme.palette.success, 0.8)],
|
||||
[theme.palette.success],
|
||||
)
|
||||
const clickHandler = (event: React.MouseEvent) => {
|
||||
if (disabled) return
|
||||
onClick && onClick(event)
|
||||
}
|
||||
|
||||
return (
|
||||
<li>
|
||||
<button
|
||||
className={`${active ? 'active' : ''} ${disabled ? 'disabled' : ''}`}
|
||||
onClick={clickHandler}
|
||||
{...props}>
|
||||
{children}
|
||||
</button>
|
||||
<style jsx>{`
|
||||
li {
|
||||
margin-right: 6px;
|
||||
display: inline-block;
|
||||
}
|
||||
button {
|
||||
border: none;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-sizing: border-box;
|
||||
text-transform: capitalize;
|
||||
user-select: none;
|
||||
white-space: nowrap;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
box-shadow: none;
|
||||
outline: none;
|
||||
height: var(--pagination-size);
|
||||
min-width: var(--pagination-size);
|
||||
font-size: inherit;
|
||||
cursor: pointer;
|
||||
color: ${theme.palette.success};
|
||||
border-radius: ${theme.layout.radius};
|
||||
background-color: ${theme.palette.background};
|
||||
transition: all linear 200ms 0ms;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: ${hover};
|
||||
}
|
||||
|
||||
.active {
|
||||
font-weight: bold;
|
||||
background-color: ${theme.palette.success};
|
||||
color: ${theme.palette.background};
|
||||
box-shadow: ${theme.expressiveness.shadowSmall};
|
||||
}
|
||||
|
||||
.active:hover {
|
||||
background-color: ${activeHover};
|
||||
box-shadow: ${theme.expressiveness.shadowMedium};
|
||||
}
|
||||
|
||||
.disabled {
|
||||
color: ${theme.palette.accents_4};
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.disabled:hover {
|
||||
background-color: ${theme.palette.accents_2};
|
||||
}
|
||||
|
||||
button :global(svg) {
|
||||
width: 1.3em;
|
||||
height: 1.3em;
|
||||
}
|
||||
`}</style>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
||||
export default PaginationItem
|
||||
19
components/pagination/pagination-next.tsx
Normal file
19
components/pagination/pagination-next.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import React from 'react'
|
||||
import PaginationItem from './pagination-item'
|
||||
import { usePaginationContext } from './pagination-context'
|
||||
|
||||
export type PaginationNextProps = React.ButtonHTMLAttributes<any>
|
||||
|
||||
const PaginationNext: React.FC<React.PropsWithChildren<PaginationNextProps>> = ({
|
||||
children,
|
||||
...props
|
||||
}) => {
|
||||
const { update, isLast } = usePaginationContext()
|
||||
return (
|
||||
<PaginationItem onClick={() => update && update('next')} disabled={isLast} {...props}>
|
||||
{children}
|
||||
</PaginationItem>
|
||||
)
|
||||
}
|
||||
|
||||
export default PaginationNext
|
||||
104
components/pagination/pagination-pages.tsx
Normal file
104
components/pagination/pagination-pages.tsx
Normal file
@@ -0,0 +1,104 @@
|
||||
import React, { Dispatch, SetStateAction, useCallback, useMemo } from 'react'
|
||||
import PaginationItem from './pagination-item'
|
||||
import PaginationEllipsis from './pagination-ellipsis'
|
||||
|
||||
interface Props {
|
||||
limit: number
|
||||
count: number
|
||||
current: number
|
||||
setPage: Dispatch<SetStateAction<number>>
|
||||
}
|
||||
|
||||
const PaginationPages: React.FC<Props> = ({ limit, count, current, setPage }) => {
|
||||
const showPages = useMemo(() => {
|
||||
const oddLimit = limit % 2 === 0 ? limit - 1 : limit
|
||||
return oddLimit - 2
|
||||
}, [limit])
|
||||
const middleNumber = (showPages + 1) / 2
|
||||
|
||||
const [showBeforeEllipsis, showAfterEllipsis] = useMemo(() => {
|
||||
const showEllipsis = count > limit
|
||||
return [
|
||||
showEllipsis && current > middleNumber + 1,
|
||||
showEllipsis && current < count - middleNumber,
|
||||
]
|
||||
}, [current, showPages, middleNumber, count, limit])
|
||||
const pagesArray = useMemo(() => [...new Array(showPages)], [showPages])
|
||||
|
||||
const renderItem = useCallback(
|
||||
(value: number, active: number) => (
|
||||
<PaginationItem
|
||||
key={`pagination-item-${value}`}
|
||||
active={value === active}
|
||||
onClick={() => setPage(value)}>
|
||||
{value}
|
||||
</PaginationItem>
|
||||
),
|
||||
[],
|
||||
)
|
||||
const startPages = pagesArray.map((_, index) => {
|
||||
const value = index + 2
|
||||
return renderItem(value, current)
|
||||
})
|
||||
const middlePages = pagesArray.map((_, index) => {
|
||||
const middleIndexNumber = middleNumber - (index + 1)
|
||||
const value = current - middleIndexNumber
|
||||
return (
|
||||
<PaginationItem
|
||||
key={`pagination-middle-${index}`}
|
||||
active={index + 1 === middleNumber}
|
||||
onClick={() => setPage(value)}>
|
||||
{value}
|
||||
</PaginationItem>
|
||||
)
|
||||
})
|
||||
const endPages = pagesArray.map((_, index) => {
|
||||
const value = count - (showPages - index)
|
||||
return renderItem(value, current)
|
||||
})
|
||||
if (count <= limit) {
|
||||
/* eslint-disable react/jsx-no-useless-fragment */
|
||||
return (
|
||||
<>
|
||||
{[...new Array(count)].map((_, index) => {
|
||||
const value = index + 1
|
||||
return (
|
||||
<PaginationItem
|
||||
key={`pagination-item-${value}`}
|
||||
active={value === current}
|
||||
onClick={() => setPage(value)}>
|
||||
{value}
|
||||
</PaginationItem>
|
||||
)
|
||||
})}
|
||||
</>
|
||||
)
|
||||
/* eslint-enable */
|
||||
}
|
||||
return (
|
||||
<>
|
||||
{renderItem(1, current)}
|
||||
{showBeforeEllipsis && (
|
||||
<PaginationEllipsis
|
||||
key="pagination-ellipsis-before"
|
||||
isBefore
|
||||
onClick={() => setPage(last => (last - 5 >= 1 ? last - 5 : 1))}
|
||||
/>
|
||||
)}
|
||||
{showBeforeEllipsis && showAfterEllipsis
|
||||
? middlePages
|
||||
: showBeforeEllipsis
|
||||
? endPages
|
||||
: startPages}
|
||||
{showAfterEllipsis && (
|
||||
<PaginationEllipsis
|
||||
key="pagination-ellipsis-after"
|
||||
onClick={() => setPage(last => (last + 5 <= count ? last + 5 : count))}
|
||||
/>
|
||||
)}
|
||||
{renderItem(count, current)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default PaginationPages
|
||||
19
components/pagination/pagination-previous.tsx
Normal file
19
components/pagination/pagination-previous.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import React from 'react'
|
||||
import PaginationItem from './pagination-item'
|
||||
import { usePaginationContext } from './pagination-context'
|
||||
|
||||
export type PaginationNextProps = React.ButtonHTMLAttributes<any>
|
||||
|
||||
const PaginationPrevious: React.FC<React.PropsWithChildren<PaginationNextProps>> = ({
|
||||
children,
|
||||
...props
|
||||
}) => {
|
||||
const { update, isFirst } = usePaginationContext()
|
||||
return (
|
||||
<PaginationItem onClick={() => update && update('prev')} disabled={isFirst} {...props}>
|
||||
{children}
|
||||
</PaginationItem>
|
||||
)
|
||||
}
|
||||
|
||||
export default PaginationPrevious
|
||||
142
components/pagination/pagination.tsx
Normal file
142
components/pagination/pagination.tsx
Normal file
@@ -0,0 +1,142 @@
|
||||
import React, { useEffect, useMemo } from 'react'
|
||||
import PaginationPrevious from './pagination-previous'
|
||||
import PaginationNext from './pagination-next'
|
||||
import PaginationPages from './pagination-pages'
|
||||
import { PaginationContext, PaginationConfig, PaginationUpdateType } from './pagination-context'
|
||||
import useCurrentState from '../utils/use-current-state'
|
||||
import { pickChild } from '../utils/collections'
|
||||
import { NormalSizes } from '../utils/prop-types'
|
||||
|
||||
interface Props {
|
||||
size?: NormalSizes
|
||||
page?: number
|
||||
initialPage?: number
|
||||
count?: number
|
||||
limit?: number
|
||||
onChange?: (val: number) => void
|
||||
}
|
||||
|
||||
const defaultProps = {
|
||||
size: 'medium' as NormalSizes,
|
||||
initialPage: 1,
|
||||
count: 1,
|
||||
limit: 7,
|
||||
}
|
||||
|
||||
type NativeAttrs = Omit<React.HTMLAttributes<any>, keyof Props>
|
||||
export type PaginationProps = Props & typeof defaultProps & NativeAttrs
|
||||
|
||||
type PaginationSize = {
|
||||
font: string
|
||||
width: string
|
||||
}
|
||||
|
||||
const getPaginationSizes = (size: NormalSizes) => {
|
||||
const sizes: { [key in NormalSizes]: PaginationSize } = {
|
||||
mini: {
|
||||
font: '.75rem',
|
||||
width: '1.25rem',
|
||||
},
|
||||
small: {
|
||||
font: '.75rem',
|
||||
width: '1.65rem',
|
||||
},
|
||||
medium: {
|
||||
font: '.875rem',
|
||||
width: '2rem',
|
||||
},
|
||||
large: {
|
||||
font: '1rem',
|
||||
width: '2.4rem',
|
||||
},
|
||||
}
|
||||
return sizes[size]
|
||||
}
|
||||
|
||||
const Pagination: React.FC<React.PropsWithChildren<PaginationProps>> = ({
|
||||
page: customPage,
|
||||
initialPage,
|
||||
count,
|
||||
limit,
|
||||
size,
|
||||
children,
|
||||
onChange,
|
||||
}) => {
|
||||
const [page, setPage, pageRef] = useCurrentState(initialPage)
|
||||
const [, prevChildren] = pickChild(children, PaginationPrevious)
|
||||
const [, nextChildren] = pickChild(children, PaginationNext)
|
||||
|
||||
const [prevItem, nextItem] = useMemo(() => {
|
||||
const hasChildren = (c: any) => React.Children.count(c) > 0
|
||||
const prevDefault = <PaginationPrevious>prev</PaginationPrevious>
|
||||
const nextDefault = <PaginationNext>next</PaginationNext>
|
||||
return [
|
||||
hasChildren(prevChildren) ? prevChildren : prevDefault,
|
||||
hasChildren(nextChildren) ? nextChildren : nextDefault,
|
||||
]
|
||||
}, [prevChildren, nextChildren])
|
||||
const { font, width } = useMemo(() => getPaginationSizes(size), [size])
|
||||
|
||||
const update = (type: PaginationUpdateType) => {
|
||||
if (type === 'prev' && pageRef.current > 1) {
|
||||
setPage(last => last - 1)
|
||||
}
|
||||
if (type === 'next' && pageRef.current < count) {
|
||||
setPage(last => last + 1)
|
||||
}
|
||||
}
|
||||
const values = useMemo<PaginationConfig>(
|
||||
() => ({
|
||||
isFirst: page <= 1,
|
||||
isLast: page >= count,
|
||||
update,
|
||||
}),
|
||||
[page],
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
onChange && onChange(page)
|
||||
}, [page])
|
||||
useEffect(() => {
|
||||
if (customPage !== undefined) {
|
||||
setPage(customPage)
|
||||
}
|
||||
}, [customPage])
|
||||
|
||||
return (
|
||||
<PaginationContext.Provider value={values}>
|
||||
<nav>
|
||||
{prevItem}
|
||||
<PaginationPages count={count} current={page} limit={limit} setPage={setPage} />
|
||||
{nextItem}
|
||||
</nav>
|
||||
<style jsx>{`
|
||||
nav {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-variant: tabular-nums;
|
||||
font-feature-settings: 'tnum';
|
||||
font-size: ${font};
|
||||
--pagination-size: ${width};
|
||||
}
|
||||
|
||||
nav :global(button:last-of-type) {
|
||||
margin-right: 0;
|
||||
}
|
||||
`}</style>
|
||||
</PaginationContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
type MemoPaginationComponent<P = {}> = React.NamedExoticComponent<P> & {
|
||||
Previous: typeof PaginationPrevious
|
||||
Next: typeof PaginationNext
|
||||
}
|
||||
|
||||
type ComponentProps = Partial<typeof defaultProps> &
|
||||
Omit<Props, keyof typeof defaultProps> &
|
||||
NativeAttrs
|
||||
|
||||
Pagination.defaultProps = defaultProps
|
||||
|
||||
export default React.memo(Pagination) as MemoPaginationComponent<ComponentProps>
|
||||
@@ -414,7 +414,7 @@ exports[`Progress should work with different types 1`] = `
|
||||
bottom: 0;
|
||||
transition: all 100ms ease-in;
|
||||
border-radius: 5px;
|
||||
background-color: #ff0000;
|
||||
background-color: #e00;
|
||||
width: 1%;
|
||||
}
|
||||
</style></div></div>"
|
||||
|
||||
@@ -61,6 +61,28 @@ describe('Radio Group', () => {
|
||||
changeHandler.mockRestore()
|
||||
})
|
||||
|
||||
it('the radio value should be support number', () => {
|
||||
let value = ''
|
||||
const changeHandler = jest.fn().mockImplementation(val => (value = val))
|
||||
const wrapper = mount(
|
||||
<Radio.Group onChange={changeHandler}>
|
||||
<Radio value={5}>Option 1</Radio>
|
||||
<Radio value={10}>Option 2</Radio>
|
||||
</Radio.Group>,
|
||||
)
|
||||
|
||||
wrapper
|
||||
.find('input')
|
||||
.at(0)
|
||||
.simulate('change', {
|
||||
...nativeEvent,
|
||||
target: { checked: true },
|
||||
})
|
||||
expect(changeHandler).toHaveBeenCalled()
|
||||
expect(value).toEqual(5)
|
||||
changeHandler.mockRestore()
|
||||
})
|
||||
|
||||
it('should ignore events when disabled', () => {
|
||||
const changeHandler = jest.fn()
|
||||
const wrapper = mount(
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React from 'react'
|
||||
|
||||
export interface RadioConfig {
|
||||
updateState?: (value: string) => void
|
||||
updateState?: (value: string | number) => void
|
||||
disabledAll: boolean
|
||||
value?: string
|
||||
value?: string | number
|
||||
inGroup: boolean
|
||||
}
|
||||
|
||||
|
||||
@@ -4,11 +4,11 @@ import { RadioContext } from './radio-context'
|
||||
import { NormalSizes } from 'components/utils/prop-types'
|
||||
|
||||
interface Props {
|
||||
value?: string
|
||||
initialValue?: string
|
||||
value?: string | number
|
||||
initialValue?: string | number
|
||||
disabled?: boolean
|
||||
size?: NormalSizes
|
||||
onChange?: (value: string) => void
|
||||
onChange?: (value: string | number) => void
|
||||
className?: string
|
||||
useRow?: boolean
|
||||
}
|
||||
@@ -44,8 +44,8 @@ const RadioGroup: React.FC<React.PropsWithChildren<RadioGroupProps>> = ({
|
||||
useRow,
|
||||
...props
|
||||
}) => {
|
||||
const [selfVal, setSelfVal] = useState<string | undefined>(initialValue)
|
||||
const updateState = (nextValue: string) => {
|
||||
const [selfVal, setSelfVal] = useState<string | number | undefined>(initialValue)
|
||||
const updateState = (nextValue: string | number) => {
|
||||
setSelfVal(nextValue)
|
||||
onChange && onChange(nextValue)
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ export interface RadioEvent {
|
||||
|
||||
interface Props {
|
||||
checked?: boolean
|
||||
value?: string
|
||||
value?: string | number
|
||||
size?: NormalSizes
|
||||
className?: string
|
||||
disabled?: boolean
|
||||
@@ -77,7 +77,7 @@ const Radio: React.FC<React.PropsWithChildren<RadioProps>> = ({
|
||||
}
|
||||
setSelfChecked(!selfChecked)
|
||||
if (inGroup) {
|
||||
updateState && updateState(radioValue as string)
|
||||
updateState && updateState(radioValue as string | number)
|
||||
}
|
||||
onChange && onChange(selfEvent)
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ exports[`Select should render correctly 1`] = `
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
line-height: calc(1.688 * 16pt);
|
||||
min-width: 0;
|
||||
}
|
||||
</style></span></span><div class=\\"icon\\"><svg viewBox=\\"0 0 24 24\\" width=\\"1.25em\\" height=\\"1.25em\\" stroke-width=\\"1\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M6 9l6 6 6-6\\"></path><style>
|
||||
@@ -93,6 +94,7 @@ exports[`Select should render correctly 1`] = `
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
line-height: calc(1 * 16pt);
|
||||
min-width: 0;
|
||||
}
|
||||
</style></span></span><div class=\\"icon\\"><svg viewBox=\\"0 0 24 24\\" width=\\"1.25em\\" height=\\"1.25em\\" stroke-width=\\"1\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M6 9l6 6 6-6\\"></path><style>
|
||||
@@ -180,6 +182,7 @@ exports[`Select should render correctly 1`] = `
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
line-height: calc(1.344 * 16pt);
|
||||
min-width: 0;
|
||||
}
|
||||
</style></span></span><div class=\\"icon\\"><svg viewBox=\\"0 0 24 24\\" width=\\"1.25em\\" height=\\"1.25em\\" stroke-width=\\"1\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M6 9l6 6 6-6\\"></path><style>
|
||||
@@ -267,6 +270,7 @@ exports[`Select should render correctly 1`] = `
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
line-height: calc(2 * 16pt);
|
||||
min-width: 0;
|
||||
}
|
||||
</style></span></span><div class=\\"icon\\"><svg viewBox=\\"0 0 24 24\\" width=\\"1.25em\\" height=\\"1.25em\\" stroke-width=\\"1\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M6 9l6 6 6-6\\"></path><style>
|
||||
@@ -358,6 +362,7 @@ exports[`Select should work correctly with labels 1`] = `
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
line-height: calc(1.688 * 16pt);
|
||||
min-width: 0;
|
||||
}
|
||||
</style></span></span><div class=\\"icon\\"><svg viewBox=\\"0 0 24 24\\" width=\\"1.25em\\" height=\\"1.25em\\" stroke-width=\\"1\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M6 9l6 6 6-6\\"></path><style>
|
||||
@@ -467,6 +472,7 @@ initialize {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
line-height: calc(1.688 * 16pt);
|
||||
min-width: 0;
|
||||
}
|
||||
",
|
||||
@@ -708,6 +714,7 @@ initialize {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
line-height: calc(1.688 * 16pt);
|
||||
min-width: 0;
|
||||
}
|
||||
",
|
||||
@@ -817,6 +824,7 @@ initialize {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
line-height: calc(1.688 * 16pt);
|
||||
min-width: 0;
|
||||
}
|
||||
",
|
||||
@@ -1130,6 +1138,7 @@ initialize {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
line-height: calc(1.688 * 16pt);
|
||||
min-width: 0;
|
||||
}
|
||||
",
|
||||
@@ -1316,6 +1325,7 @@ initialize {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
line-height: calc(1.688 * 16pt);
|
||||
min-width: 0;
|
||||
}
|
||||
",
|
||||
|
||||
@@ -6,6 +6,7 @@ exports[`Select Multiple should render correctly 1`] = `
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
line-height: calc(1.688 * 16pt);
|
||||
min-width: 0;
|
||||
}
|
||||
</style></span></span><div class=\\"item mock \\"><style>
|
||||
@@ -32,6 +33,7 @@ exports[`Select Multiple should render correctly 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 650px) {
|
||||
@@ -39,6 +41,7 @@ exports[`Select Multiple should render correctly 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +50,7 @@ exports[`Select Multiple should render correctly 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +59,7 @@ exports[`Select Multiple should render correctly 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +68,7 @@ exports[`Select Multiple should render correctly 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +77,7 @@ exports[`Select Multiple should render correctly 1`] = `
|
||||
flex-grow: 1;
|
||||
max-width: 100%;
|
||||
flex-basis: 0;
|
||||
|
||||
}
|
||||
}
|
||||
</style></div><div class=\\"icon\\"><svg viewBox=\\"0 0 24 24\\" width=\\"1.25em\\" height=\\"1.25em\\" stroke-width=\\"1\\" stroke-linecap=\\"round\\" stroke-linejoin=\\"round\\" fill=\\"none\\" shape-rendering=\\"geometricPrecision\\"><path d=\\"M6 9l6 6 6-6\\"></path><style>
|
||||
|
||||
@@ -81,7 +81,7 @@ const SelectOption: React.FC<React.PropsWithChildren<SelectOptionProps>> = ({
|
||||
className={`option ${divider ? 'divider' : ''} ${label ? 'label' : ''} ${className}`}
|
||||
onClick={clickHandler}
|
||||
{...props}>
|
||||
<Ellipsis>{children}</Ellipsis>
|
||||
<Ellipsis height={`calc(1.688 * ${theme.layout.gap})`}>{children}</Ellipsis>
|
||||
</div>
|
||||
|
||||
<style jsx>{`
|
||||
|
||||
@@ -139,7 +139,7 @@ const Select: React.FC<React.PropsWithChildren<SelectProps>> = ({
|
||||
{...props}>
|
||||
{isEmpty && (
|
||||
<span className="value placeholder">
|
||||
<Ellipsis>{placeholder}</Ellipsis>
|
||||
<Ellipsis height={sizes.height}>{placeholder}</Ellipsis>
|
||||
</span>
|
||||
)}
|
||||
{value && !multiple && <span className="value">{selectedChild}</span>}
|
||||
|
||||
@@ -1,103 +1,5 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Backdrop content should be offset 1`] = `
|
||||
"<div class=\\"backdrop transition-enter\\"><div class=\\"layer\\"></div><div class=\\"content\\"><span>test-value</span></div><div class=\\"offset\\"></div><style>
|
||||
.backdrop {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
overflow: auto;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
z-index: 1001;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.offset {
|
||||
height: 0vh;
|
||||
opacity: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.layer {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0.25;
|
||||
background-color: black;
|
||||
transition: opacity 0.35s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
pointer-events: none;
|
||||
z-index: 1000;
|
||||
}
|
||||
</style></div>"
|
||||
`;
|
||||
|
||||
exports[`Backdrop content should be offset 2`] = `
|
||||
"<div class=\\"backdrop transition-enter\\"><div class=\\"layer\\"></div><div class=\\"content\\"><span>test-value</span></div><div class=\\"offset\\"></div><style>
|
||||
.backdrop {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
align-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
overflow: auto;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
z-index: 1001;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.offset {
|
||||
height: 100vh;
|
||||
opacity: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.layer {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0.25;
|
||||
background-color: black;
|
||||
transition: opacity 0.35s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
pointer-events: none;
|
||||
z-index: 1000;
|
||||
}
|
||||
</style></div>"
|
||||
`;
|
||||
|
||||
exports[`Backdrop should render correctly 1`] = `
|
||||
"<div class=\\"backdrop transition-enter\\"><div class=\\"layer\\"></div><div class=\\"content\\"><span>test-value</span></div><div class=\\"offset\\"></div><style>
|
||||
.backdrop {
|
||||
@@ -108,7 +10,7 @@ exports[`Backdrop should render correctly 1`] = `
|
||||
align-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
justify-content: space-around;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
overflow: auto;
|
||||
@@ -125,8 +27,9 @@ exports[`Backdrop should render correctly 1`] = `
|
||||
}
|
||||
|
||||
.offset {
|
||||
height: 0vh;
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
display: flex;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ exports[`Ellipsis should render correctly 1`] = `
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
line-height: 10px;
|
||||
min-width: 0;
|
||||
}
|
||||
</style></span></div>"
|
||||
|
||||
@@ -61,17 +61,28 @@ describe('Backdrop', () => {
|
||||
handler.mockRestore()
|
||||
})
|
||||
|
||||
it('content should be offset', () => {
|
||||
it('backdrop handler should ignore click events from content', async () => {
|
||||
const handler = jest.fn()
|
||||
const wrapper = mount(
|
||||
<Backdrop visible>
|
||||
<Backdrop visible onClick={handler}>
|
||||
<span>test-value</span>
|
||||
</Backdrop>,
|
||||
)
|
||||
const notOffset = wrapper.html()
|
||||
expect(wrapper.html()).toMatchSnapshot()
|
||||
|
||||
wrapper.setProps({ offsetY: '100' })
|
||||
expect(wrapper.html()).toMatchSnapshot()
|
||||
expect(notOffset).not.toEqual(wrapper.html())
|
||||
/**
|
||||
* In simulation,`mousedown` and `mouseup`not directly triiger `click` event,
|
||||
* the click event below is just for simulation.
|
||||
*/
|
||||
wrapper.find('.content').simulate('mousedown')
|
||||
wrapper.find('.backdrop').simulate('click', nativeEvent)
|
||||
wrapper.find('.backdrop').simulate('mouseup')
|
||||
await updateWrapper(wrapper)
|
||||
expect(handler).not.toHaveBeenCalled()
|
||||
|
||||
wrapper.find('.backdrop').simulate('mousedown')
|
||||
wrapper.find('.backdrop').simulate('click', nativeEvent)
|
||||
wrapper.find('.backdrop').simulate('mouseup')
|
||||
await updateWrapper(wrapper)
|
||||
expect(handler).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -6,7 +6,7 @@ describe('Ellipsis', () => {
|
||||
it('should render correctly', () => {
|
||||
const wrapper = mount(
|
||||
<div style={{ width: '1px' }}>
|
||||
<Ellipsis>text</Ellipsis>
|
||||
<Ellipsis height="10px">text</Ellipsis>
|
||||
</div>,
|
||||
)
|
||||
expect(wrapper.html()).toMatchSnapshot()
|
||||
|
||||
@@ -2,11 +2,11 @@ import React, { MouseEvent, useCallback } from 'react'
|
||||
import withDefaults from '../utils/with-defaults'
|
||||
import useTheme from '../styles/use-theme'
|
||||
import CSSTransition from './css-transition'
|
||||
import useCurrentState from '../utils/use-current-state'
|
||||
|
||||
interface Props {
|
||||
onClick?: (event: MouseEvent<HTMLElement>) => void
|
||||
visible?: boolean
|
||||
offsetY?: number
|
||||
}
|
||||
|
||||
const defaultProps = {
|
||||
@@ -18,20 +18,32 @@ const defaultProps = {
|
||||
export type BackdropProps = Props & typeof defaultProps
|
||||
|
||||
const Backdrop: React.FC<React.PropsWithChildren<BackdropProps>> = React.memo(
|
||||
({ children, onClick, visible, offsetY }) => {
|
||||
({ children, onClick, visible }) => {
|
||||
const theme = useTheme()
|
||||
const clickHandler = useCallback((event: MouseEvent<HTMLElement>) => {
|
||||
const [, setIsContentMouseDown, IsContentMouseDownRef] = useCurrentState(false)
|
||||
const clickHandler = (event: MouseEvent<HTMLElement>) => {
|
||||
if (IsContentMouseDownRef.current) return
|
||||
onClick && onClick(event)
|
||||
}, [])
|
||||
}
|
||||
const childrenClickHandler = useCallback((event: MouseEvent<HTMLElement>) => {
|
||||
event.stopPropagation()
|
||||
}, [])
|
||||
const mouseUpHandler = () => {
|
||||
if (!IsContentMouseDownRef.current) return
|
||||
const timer = setTimeout(() => {
|
||||
setIsContentMouseDown(false)
|
||||
clearTimeout(timer)
|
||||
}, 0)
|
||||
}
|
||||
|
||||
return (
|
||||
<CSSTransition visible={visible} clearTime={300}>
|
||||
<div className="backdrop" onClick={clickHandler}>
|
||||
<div className="backdrop" onClick={clickHandler} onMouseUp={mouseUpHandler}>
|
||||
<div className="layer" />
|
||||
<div onClick={childrenClickHandler} className="content">
|
||||
<div
|
||||
onClick={childrenClickHandler}
|
||||
className="content"
|
||||
onMouseDown={() => setIsContentMouseDown(true)}>
|
||||
{children}
|
||||
</div>
|
||||
<div onClick={childrenClickHandler} className="offset" />
|
||||
@@ -44,7 +56,7 @@ const Backdrop: React.FC<React.PropsWithChildren<BackdropProps>> = React.memo(
|
||||
align-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
justify-content: space-around;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
overflow: auto;
|
||||
@@ -61,8 +73,9 @@ const Backdrop: React.FC<React.PropsWithChildren<BackdropProps>> = React.memo(
|
||||
}
|
||||
|
||||
.offset {
|
||||
height: ${offsetY}vh;
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
display: flex;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import React from 'react'
|
||||
|
||||
const Ellipsis: React.FC<React.PropsWithChildren<{}>> = ({ children }) => {
|
||||
export type EllipsisProps = {
|
||||
height: string
|
||||
}
|
||||
|
||||
const Ellipsis: React.FC<React.PropsWithChildren<EllipsisProps>> = ({ children, height }) => {
|
||||
return (
|
||||
<span>
|
||||
{children}
|
||||
@@ -9,6 +13,7 @@ const Ellipsis: React.FC<React.PropsWithChildren<{}>> = ({ children }) => {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
line-height: ${height};
|
||||
min-width: 0;
|
||||
}
|
||||
`}</style>
|
||||
|
||||
@@ -18,19 +18,29 @@ export const palette: ZeitUIThemesPalette = {
|
||||
secondary: '#888',
|
||||
code: '#79ffe1',
|
||||
border: '#333',
|
||||
error: '#ff0000',
|
||||
error: '#e00',
|
||||
errorLighter: '#f7d4d6',
|
||||
errorLight: '#ff1a1a',
|
||||
errorDark: '#c00',
|
||||
errorDark: '#c50000',
|
||||
success: '#0070f3',
|
||||
successLighter: '#d3e5ff',
|
||||
successLight: '#3291ff',
|
||||
successDark: '#0366d6',
|
||||
successDark: '#0761d1',
|
||||
warning: '#f5a623',
|
||||
warningLighter: '#ffefcf',
|
||||
warningLight: '#f7b955',
|
||||
warningDark: '#f49b0b',
|
||||
cyan: '#79ffe1',
|
||||
warningDark: '#ab570a',
|
||||
cyan: '#50e3c2',
|
||||
cyanLighter: '#aaffec',
|
||||
cyanLight: '#79ffe1',
|
||||
cyanDark: '#29bc9b',
|
||||
violet: '#7928ca',
|
||||
violetLighter: '#e3d7fc',
|
||||
violetLight: '#8a63d2',
|
||||
violetDark: '#4c2889',
|
||||
purple: '#f81ce5',
|
||||
alert: '#ff0080',
|
||||
violet: '#7928ca',
|
||||
magenta: '#eb367f',
|
||||
link: '#3291ff',
|
||||
}
|
||||
|
||||
|
||||
@@ -18,19 +18,29 @@ export const palette: ZeitUIThemesPalette = {
|
||||
secondary: '#666',
|
||||
code: '#f81ce5',
|
||||
border: '#eaeaea',
|
||||
error: '#ff0000',
|
||||
error: '#e00',
|
||||
errorLight: '#ff1a1a',
|
||||
errorDark: '#c00',
|
||||
errorLighter: '#f7d4d6',
|
||||
errorDark: '#c50000',
|
||||
success: '#0070f3',
|
||||
successLight: '#3291ff',
|
||||
successDark: '#0366d6',
|
||||
successLighter: '#d3e5ff',
|
||||
successDark: '#0761d1',
|
||||
warning: '#f5a623',
|
||||
warningLight: '#f7b955',
|
||||
warningDark: '#f49b0b',
|
||||
cyan: '#79ffe1',
|
||||
warningLighter: '#ffefcf',
|
||||
warningDark: '#ab570a',
|
||||
cyan: '#50e3c2',
|
||||
cyanLighter: '#aaffec',
|
||||
cyanLight: '#79ffe1',
|
||||
cyanDark: '#29bc9b',
|
||||
violet: '#7928ca',
|
||||
violetLighter: '#e3d7fc',
|
||||
violetLight: '#8a63d2',
|
||||
violetDark: '#4c2889',
|
||||
purple: '#f81ce5',
|
||||
alert: '#ff0080',
|
||||
violet: '#7928ca',
|
||||
magenta: '#eb367f',
|
||||
link: '#0070f3',
|
||||
}
|
||||
|
||||
|
||||
@@ -18,19 +18,29 @@ export interface ZeitUIThemesPalette {
|
||||
code: string
|
||||
border: string
|
||||
success: string
|
||||
successLighter: string
|
||||
successLight: string
|
||||
successDark: string
|
||||
error: string
|
||||
errorLighter: string
|
||||
errorLight: string
|
||||
errorDark: string
|
||||
warning: string
|
||||
warningLighter: string
|
||||
warningLight: string
|
||||
warningDark: string
|
||||
cyan: string
|
||||
purple: string
|
||||
alert: string
|
||||
cyanLighter: string
|
||||
cyanLight: string
|
||||
cyanDark: string
|
||||
violet: string
|
||||
violetLighter: string
|
||||
violetLight: string
|
||||
violetDark: string
|
||||
link: string
|
||||
purple: string
|
||||
magenta: string
|
||||
alert: string
|
||||
}
|
||||
|
||||
export interface ZeitUIThemesExpressiveness {
|
||||
|
||||
@@ -319,9 +319,9 @@ initialize {
|
||||
font-size: 0.875rem;
|
||||
height: 1.75rem;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #ff0000;
|
||||
border: 1px solid #e00;
|
||||
background-color: #fff;
|
||||
color: #ff0000;
|
||||
color: #e00;
|
||||
padding: 6px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
@@ -356,9 +356,9 @@ initialize {
|
||||
font-size: 0.875rem;
|
||||
height: 1.75rem;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #ff0000;
|
||||
border: 1px solid #e00;
|
||||
background-color: #fff;
|
||||
color: #ff0000;
|
||||
color: #e00;
|
||||
padding: 6px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
@@ -618,9 +618,9 @@ initialize {
|
||||
font-size: 0.875rem;
|
||||
height: 1.75rem;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #ff0000;
|
||||
border: 1px solid #e00;
|
||||
background-color: #fff;
|
||||
color: #ff0000;
|
||||
color: #e00;
|
||||
padding: 6px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
@@ -655,9 +655,9 @@ initialize {
|
||||
font-size: 0.875rem;
|
||||
height: 1.75rem;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #ff0000;
|
||||
border: 1px solid #e00;
|
||||
background-color: #fff;
|
||||
color: #ff0000;
|
||||
color: #e00;
|
||||
padding: 6px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
@@ -917,9 +917,9 @@ initialize {
|
||||
font-size: 0.875rem;
|
||||
height: 1.75rem;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #ff0000;
|
||||
border: 1px solid #e00;
|
||||
background-color: #fff;
|
||||
color: #ff0000;
|
||||
color: #e00;
|
||||
padding: 6px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
@@ -954,9 +954,9 @@ initialize {
|
||||
font-size: 0.875rem;
|
||||
height: 1.75rem;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #ff0000;
|
||||
border: 1px solid #e00;
|
||||
background-color: #fff;
|
||||
color: #ff0000;
|
||||
color: #e00;
|
||||
padding: 6px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
@@ -1390,9 +1390,9 @@ initialize {
|
||||
font-size: 0.875rem;
|
||||
height: 1.75rem;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #ff0000;
|
||||
border: 1px solid #e00;
|
||||
background-color: #fff;
|
||||
color: #ff0000;
|
||||
color: #e00;
|
||||
padding: 6px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
@@ -1427,9 +1427,9 @@ initialize {
|
||||
font-size: 0.875rem;
|
||||
height: 1.75rem;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #ff0000;
|
||||
border: 1px solid #e00;
|
||||
background-color: #fff;
|
||||
color: #ff0000;
|
||||
color: #e00;
|
||||
padding: 6px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ exports[`Text should work with different styles 1`] = `
|
||||
}
|
||||
</style><p class=\\" \\">test-value</p><style>
|
||||
p {
|
||||
color: #ff0000;
|
||||
color: #e00;
|
||||
}
|
||||
|
||||
.custom-size {
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
## Custom styles
|
||||
|
||||
This is an example of **how to override styles in `zeit-ui`**.
|
||||
|
||||
## Getting Started
|
||||
|
||||
First, run the development server:
|
||||
|
||||
```bash
|
||||
npm i && npm run dev
|
||||
# or
|
||||
yarn && yarn dev
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"build": "react-scripts build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@zeit-ui/react": "^0.0.1-beta.25",
|
||||
"@zeit-ui/react": "latest",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1"
|
||||
},
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import React from 'react'
|
||||
import ReactDom from 'react-dom'
|
||||
import { ZEITUIProvider, CSSBaseline } from '@zeit-ui/react'
|
||||
import { ZeitProvider, CssBaseline } from '@zeit-ui/react'
|
||||
import Home from './home'
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
<ZEITUIProvider>
|
||||
<CSSBaseline />
|
||||
<ZeitProvider>
|
||||
<CssBaseline />
|
||||
<Home />
|
||||
</ZEITUIProvider>
|
||||
</ZeitProvider>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,15 @@
|
||||
## Custom themes example
|
||||
## Custom themes
|
||||
|
||||
This is an example of **how to custom Themes in `zeit-ui`**.
|
||||
|
||||
## Getting Started
|
||||
|
||||
First, run the development server:
|
||||
|
||||
```bash
|
||||
npm i && npm run dev
|
||||
# or
|
||||
yarn && yarn dev
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
"build": "react-scripts build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@zeit-ui/react": "^0.0.1-beta.17",
|
||||
"@zeit-ui/react": "latest",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1"
|
||||
},
|
||||
|
||||
@@ -5,7 +5,7 @@ const Home = () => {
|
||||
const theme = useTheme()
|
||||
|
||||
return (
|
||||
<Card shadow style={{ width: '500px', margin: '100px auto' }}>
|
||||
<Card shadow>
|
||||
<Text>Modern and minimalist React UI library.</Text>
|
||||
<Text type={'success'}>
|
||||
Modern and minimalist React UI library. <Tag>{theme.palette.success}</Tag>
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
import React from 'react'
|
||||
import ReactDom from 'react-dom'
|
||||
import { ZEITUIProvider, CSSBaseline } from '@zeit-ui/react'
|
||||
import { ZeitProvider, CssBaseline, Page } from '@zeit-ui/react'
|
||||
import Home from './home'
|
||||
import Theme from './theme'
|
||||
|
||||
const App = () => {
|
||||
return (
|
||||
<ZEITUIProvider theme={Theme}>
|
||||
<CSSBaseline />
|
||||
<Home />
|
||||
</ZEITUIProvider>
|
||||
<ZeitProvider theme={Theme}>
|
||||
<CssBaseline />
|
||||
<Page size="mini">
|
||||
<Home />
|
||||
</Page>
|
||||
</ZeitProvider>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
15
examples/extends-components/README.md
Normal file
15
examples/extends-components/README.md
Normal file
@@ -0,0 +1,15 @@
|
||||
## Extends Components
|
||||
|
||||
This is an example of **how to inherit components in `zeit-ui`**.
|
||||
|
||||
## Getting Started
|
||||
|
||||
First, run the development server:
|
||||
|
||||
```bash
|
||||
npm i && npm run dev
|
||||
# or
|
||||
yarn && yarn dev
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
26
examples/extends-components/package.json
Normal file
26
examples/extends-components/package.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "zeit-ui-react-extends-components",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
"@zeit-ui/react": "latest",
|
||||
"react": "^16.12.0",
|
||||
"react-dom": "^16.12.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "16.9.19",
|
||||
"@types/react-dom": "16.9.5",
|
||||
"react-scripts": "^3.4.1",
|
||||
"typescript": "3.7.5"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "react-scripts start",
|
||||
"build": "react-scripts build"
|
||||
},
|
||||
"browserslist": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not ie <= 11",
|
||||
"not op_mini all"
|
||||
]
|
||||
}
|
||||
11
examples/extends-components/public/index.html
Normal file
11
examples/extends-components/public/index.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Extends Components</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
</html>
|
||||
14
examples/extends-components/src/app.tsx
Normal file
14
examples/extends-components/src/app.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import * as React from 'react'
|
||||
import MyInput from './my-input'
|
||||
import { ZeitProvider, CssBaseline, Page } from '@zeit-ui/react'
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<ZeitProvider>
|
||||
<CssBaseline />
|
||||
<Page size="mini">
|
||||
<MyInput error="this is required" placeholder="my input" />
|
||||
</Page>
|
||||
</ZeitProvider>
|
||||
)
|
||||
}
|
||||
7
examples/extends-components/src/index.tsx
Normal file
7
examples/extends-components/src/index.tsx
Normal file
@@ -0,0 +1,7 @@
|
||||
import * as React from 'react'
|
||||
import { render } from 'react-dom'
|
||||
|
||||
import App from './app'
|
||||
|
||||
const rootElement = document.getElementById('app')
|
||||
render(<App />, rootElement)
|
||||
29
examples/extends-components/src/my-input.tsx
Normal file
29
examples/extends-components/src/my-input.tsx
Normal file
@@ -0,0 +1,29 @@
|
||||
import React, { ReactElement } from 'react'
|
||||
import { Input, Spacer, Text } from '@zeit-ui/react'
|
||||
|
||||
type InputErrorType = {
|
||||
error?: string
|
||||
}
|
||||
|
||||
const MyInput: React.FC<InputErrorType & React.ComponentProps<typeof Input>> = ({
|
||||
error = null,
|
||||
...inputProps
|
||||
}): ReactElement => {
|
||||
const hasError = Boolean(error)
|
||||
const { status } = inputProps
|
||||
return (
|
||||
<>
|
||||
<Input status={hasError ? 'error' : status} {...inputProps} />
|
||||
{hasError && (
|
||||
<>
|
||||
<Spacer y={0.4} />
|
||||
<Text small type="error" size="var(--size-xs2)">
|
||||
{error}
|
||||
</Text>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default MyInput
|
||||
1
examples/extends-components/src/react-app-env.d.ts
vendored
Normal file
1
examples/extends-components/src/react-app-env.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference types="react-scripts" />
|
||||
24
examples/extends-components/tsconfig.json
Normal file
24
examples/extends-components/tsconfig.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"include": [
|
||||
"./src/*"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"lib": [
|
||||
"dom",
|
||||
"es2015"
|
||||
],
|
||||
"jsx": "react",
|
||||
"target": "es5",
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
"analyze": "source-map-explorer 'build/static/js/*.js'"
|
||||
},
|
||||
"dependencies": {
|
||||
"@zeit-ui/react": "^1.5.0-rc.0",
|
||||
"@zeit-ui/react": "latest",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1"
|
||||
},
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
14
examples/tree-shaking-nextjs/.babelrc
Normal file
14
examples/tree-shaking-nextjs/.babelrc
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"presets": [
|
||||
"next/babel"
|
||||
],
|
||||
"plugins": [
|
||||
[
|
||||
"import",
|
||||
{
|
||||
"libraryName": "@zeit-ui/react",
|
||||
"libraryDirectory": "esm"
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
53
examples/tree-shaking-nextjs/README.md
Normal file
53
examples/tree-shaking-nextjs/README.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# Tree shaking with Next.js
|
||||
|
||||
## About
|
||||
|
||||
This is example of `tree-shaking` for [next.js](https://nextjs.com/). Note that `@next/bundle-analyzer` is not required.
|
||||
|
||||
## Getting Started
|
||||
|
||||
First, run the development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
# or
|
||||
yarn dev
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
|
||||
**Run the following command to see the size of the bundle:**
|
||||
|
||||
```bash
|
||||
npm run analyze
|
||||
# or
|
||||
yarn analyze
|
||||
```
|
||||
|
||||
## Preview
|
||||
|
||||
If we don't do anything, the volume of `zeit-ui/react` is about `58kb`, note that **the volume here includes lib `styled-jsx`**.
|
||||
It means that even if you use lib `styled-jsx` again, the volume will not increase.
|
||||
|
||||
At present, it seems that this volume of component library is still acceptable:
|
||||
|
||||

|
||||
|
||||
<br/>
|
||||
|
||||
**When we use `tree shaking`:**
|
||||
|
||||
The volume of `zeit-ui/react` is about `13kb`.(It consists of two parts)
|
||||
It should be noted that the specific package size depends on how many components you use.
|
||||
|
||||

|
||||
|
||||
## Other
|
||||
|
||||
If you don't use `tree shaking` in your porject, bundle `zeit-ui/react` as a `chunk`
|
||||
every time, you may notice that the hash name of `chunk` is still changing,
|
||||
this may cause you to not make full use of the cache.
|
||||
|
||||
- This issue from `next.js`, and they're improving that, you can track progress [here](https://github.com/vercel/next.js/issues/6303).
|
||||
- If you want to customize config of webpack, to ensure that the `chunk` from `zeit-ui/react` is always the same,
|
||||
you can refer to [this docuemnt](https://webpack.js.org/guides/code-splitting/).
|
||||
6
examples/tree-shaking-nextjs/next.config.js
Normal file
6
examples/tree-shaking-nextjs/next.config.js
Normal file
@@ -0,0 +1,6 @@
|
||||
const withTM = require('next-transpile-modules')(['@zeit-ui/react'])
|
||||
const withBundleAnalyzer = require('@next/bundle-analyzer')({
|
||||
enabled: process.env.ANALYZE === 'true',
|
||||
})
|
||||
|
||||
module.exports = withTM(withBundleAnalyzer({}))
|
||||
22
examples/tree-shaking-nextjs/package.json
Normal file
22
examples/tree-shaking-nextjs/package.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "tree-shaking-nextjs",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"analyze": "ANALYZE=true yarn build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@zeit-ui/react": "latest",
|
||||
"next": "9.4.2",
|
||||
"react": "16.13.1",
|
||||
"react-dom": "16.13.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@next/bundle-analyzer": "^9.4.4",
|
||||
"babel-plugin-import": "^1.13.0",
|
||||
"next-transpile-modules": "^3.3.0"
|
||||
}
|
||||
}
|
||||
11
examples/tree-shaking-nextjs/pages/_app.js
Normal file
11
examples/tree-shaking-nextjs/pages/_app.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import { ZeitProvider, CssBaseline } from '@zeit-ui/react'
|
||||
|
||||
function MyApp({ Component, pageProps }) {
|
||||
return (
|
||||
<ZeitProvider>
|
||||
<CssBaseline />
|
||||
<Component {...pageProps} />
|
||||
</ZeitProvider>
|
||||
)
|
||||
}
|
||||
export default MyApp
|
||||
33
examples/tree-shaking-nextjs/pages/_document.js
Normal file
33
examples/tree-shaking-nextjs/pages/_document.js
Normal file
@@ -0,0 +1,33 @@
|
||||
import Document, { Html, Head, Main, NextScript } from 'next/document'
|
||||
import { CssBaseline } from '@zeit-ui/react'
|
||||
|
||||
class MyDocument extends Document {
|
||||
static async getInitialProps(ctx) {
|
||||
const initialProps = await Document.getInitialProps(ctx)
|
||||
const styles = CssBaseline.flush()
|
||||
|
||||
return {
|
||||
...initialProps,
|
||||
styles: (
|
||||
<>
|
||||
{initialProps.styles}
|
||||
{styles}
|
||||
</>
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Html>
|
||||
<Head />
|
||||
<body>
|
||||
<Main />
|
||||
<NextScript />
|
||||
</body>
|
||||
</Html>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default MyDocument
|
||||
12
examples/tree-shaking-nextjs/pages/index.js
Normal file
12
examples/tree-shaking-nextjs/pages/index.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import { Page, Text, Button } from '@zeit-ui/react'
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<Page>
|
||||
<Text h1>
|
||||
Welcome to <a href="https://nextjs.org">Next.js!</a>
|
||||
</Text>
|
||||
<Button>hello</Button>
|
||||
</Page>
|
||||
)
|
||||
}
|
||||
BIN
examples/tree-shaking-nextjs/public/favicon.ico
Normal file
BIN
examples/tree-shaking-nextjs/public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
BIN
examples/tree-shaking-nextjs/public/output-after.png
Normal file
BIN
examples/tree-shaking-nextjs/public/output-after.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 105 KiB |
BIN
examples/tree-shaking-nextjs/public/output-before.png
Normal file
BIN
examples/tree-shaking-nextjs/public/output-before.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 101 KiB |
@@ -21,7 +21,7 @@
|
||||
"webpack-dev-server": "^3.11.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@zeit-ui/react": "^1.5.0-rc.0",
|
||||
"@zeit-ui/react": "latest",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1"
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -56,14 +56,14 @@ const Controls: React.FC<{}> = React.memo(({}) => {
|
||||
value={isDark ? 'dark' : 'light'}
|
||||
title={isChinese ? '切换主题' : 'Switch Themes'}>
|
||||
<Select.Option value="light">
|
||||
<div className="select-content">
|
||||
<span className="select-content">
|
||||
<SunIcon size={14} /> {isChinese ? '明亮' : 'Light'}
|
||||
</div>
|
||||
</span>
|
||||
</Select.Option>
|
||||
<Select.Option value="dark">
|
||||
<div className="select-content">
|
||||
<span className="select-content">
|
||||
<MoonIcon size={14} /> {isChinese ? '暗黑' : 'Dark'}
|
||||
</div>
|
||||
</span>
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</div>
|
||||
@@ -82,7 +82,8 @@ const Controls: React.FC<{}> = React.memo(({}) => {
|
||||
|
||||
.select-content {
|
||||
width: auto;
|
||||
display: inline-flex;
|
||||
height: 18px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@@ -20,28 +20,44 @@ const normal: ColorEnum = {
|
||||
/* eslint-enable camelcase */
|
||||
|
||||
const error: ColorEnum = {
|
||||
errorLighter: 'Lighter',
|
||||
errorLight: 'Light',
|
||||
error: 'Default',
|
||||
errorDark: 'Dark',
|
||||
}
|
||||
|
||||
const success: ColorEnum = {
|
||||
successLighter: 'Lighter',
|
||||
successLight: 'Light',
|
||||
success: 'Default',
|
||||
successDark: 'Dark',
|
||||
}
|
||||
|
||||
const warning: ColorEnum = {
|
||||
warningLighter: 'Lighter',
|
||||
warningLight: 'Light',
|
||||
warning: 'Default',
|
||||
warningDark: 'Dark',
|
||||
}
|
||||
|
||||
const violet: ColorEnum = {
|
||||
violetLighter: 'Lighter',
|
||||
violetLight: 'Light',
|
||||
violet: 'Default',
|
||||
violetDark: 'Dark',
|
||||
}
|
||||
|
||||
const cyan: ColorEnum = {
|
||||
cyanLighter: 'Lighter',
|
||||
cyanLight: 'Light',
|
||||
cyan: 'Default',
|
||||
cyanDark: 'Dark',
|
||||
}
|
||||
|
||||
const highlight: ColorEnum = {
|
||||
alert: 'Alert',
|
||||
purple: 'Purple',
|
||||
violet: 'Violet',
|
||||
cyan: 'Cyan',
|
||||
magenta: 'Violet',
|
||||
}
|
||||
|
||||
const colorsData: { [key: string]: ColorEnum } = {
|
||||
@@ -49,6 +65,8 @@ const colorsData: { [key: string]: ColorEnum } = {
|
||||
success,
|
||||
warning,
|
||||
error,
|
||||
violet,
|
||||
cyan,
|
||||
highlight,
|
||||
}
|
||||
|
||||
@@ -72,5 +90,15 @@ export const getCurrentColor = (
|
||||
return 'black'
|
||||
}
|
||||
|
||||
if (type === 'warning' || type === 'cyan') {
|
||||
if (index < 3) return 'black'
|
||||
return 'white'
|
||||
}
|
||||
|
||||
if (Object.keys(colorsData[type]).find(key => key.endsWith('Lighter'))) {
|
||||
if (index === 0) return 'black'
|
||||
return 'white'
|
||||
}
|
||||
|
||||
return palette.background
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useMemo } from 'react'
|
||||
import { useTheme, useToasts, Code, ZeitUIThemesPalette } from 'components'
|
||||
import { useTheme, useToasts, Code, Grid, ZeitUIThemesPalette } from 'components'
|
||||
import useClipboard from 'components/utils/use-clipboard'
|
||||
import { getColorData, getCurrentColor } from './colors-data'
|
||||
|
||||
@@ -14,13 +14,21 @@ const getColorItem = (type: string, palette: ZeitUIThemesPalette, copy: Function
|
||||
|
||||
return (keys as Array<keyof ZeitUIThemesPalette>).map((key, index) => (
|
||||
<div className="color" key={`color-item-${index}`}>
|
||||
<h4>{data[key]}</h4>
|
||||
<span className="usage" onClick={() => copy(`theme.palette.${key}`)}>
|
||||
theme.palette.{key}
|
||||
</span>
|
||||
<span className="value" onClick={() => copy(palette[key])}>
|
||||
{palette[key]}
|
||||
</span>
|
||||
<Grid.Container justify="space-between" style={{ height: '4.5rem' }}>
|
||||
<Grid.Container alignItems="center" sm={8} xs={16}>
|
||||
<h4>{data[key]}</h4>
|
||||
</Grid.Container>
|
||||
<Grid.Container alignItems="center" justify="center" sm={8} xs={0}>
|
||||
<span className="usage" onClick={() => copy(`theme.palette.${key}`)}>
|
||||
theme.palette.{key}
|
||||
</span>
|
||||
</Grid.Container>
|
||||
<Grid.Container alignItems="center" justify="flex-end" sm={8} xs>
|
||||
<span className="value" onClick={() => copy(palette[key])}>
|
||||
{palette[key]}
|
||||
</span>
|
||||
</Grid.Container>
|
||||
</Grid.Container>
|
||||
<style jsx>{`
|
||||
.color {
|
||||
background-color: ${palette[key]};
|
||||
@@ -61,13 +69,8 @@ const Colors: React.FC<Props> = ({ type }) => {
|
||||
}
|
||||
|
||||
.colors :global(.color) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: ${theme.layout.gap};
|
||||
height: 6rem;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
@@ -86,18 +89,16 @@ const Colors: React.FC<Props> = ({ type }) => {
|
||||
}
|
||||
|
||||
.colors :global(.usage) {
|
||||
font-size: 0.875rem;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: 1rem;
|
||||
padding: 1rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.colors :global(.value) {
|
||||
font-size: 0.875rem;
|
||||
text-transform: uppercase;
|
||||
padding: 1rem 0;
|
||||
padding: 1rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
|
||||
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user