mirror of
https://github.com/zhigang1992/react.git
synced 2026-04-28 20:25:29 +08:00
style(prettier): format code style
This commit is contained in:
@@ -4,36 +4,48 @@ import { Tree } from 'components'
|
||||
import { nativeEvent } from 'tests/utils'
|
||||
import { FileTreeValue } from 'components/file-tree/tree'
|
||||
|
||||
const mockFiles: Array<FileTreeValue> = [{
|
||||
type: 'file',
|
||||
name: 'cs.js',
|
||||
}, {
|
||||
type: 'directory',
|
||||
name: 'bin',
|
||||
files: [{
|
||||
const mockFiles: Array<FileTreeValue> = [
|
||||
{
|
||||
type: 'file',
|
||||
name: 'cs.js',
|
||||
}],
|
||||
}, {
|
||||
type: 'directory',
|
||||
name: 'docs',
|
||||
files: [{
|
||||
type: 'file',
|
||||
name: 'controllers.md',
|
||||
}, {
|
||||
type: 'file',
|
||||
name: 'es6.md',
|
||||
}, {
|
||||
type: 'file',
|
||||
name: 'production.md',
|
||||
}, {
|
||||
},
|
||||
{
|
||||
type: 'directory',
|
||||
name: 'bin',
|
||||
files: [
|
||||
{
|
||||
type: 'file',
|
||||
name: 'cs.js',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'directory',
|
||||
name: 'docs',
|
||||
files: [
|
||||
{
|
||||
type: 'file',
|
||||
name: 'controllers.md',
|
||||
},
|
||||
{
|
||||
type: 'file',
|
||||
name: 'es6.md',
|
||||
},
|
||||
{
|
||||
type: 'file',
|
||||
name: 'production.md',
|
||||
},
|
||||
{
|
||||
type: 'file',
|
||||
name: 'views.md',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'file',
|
||||
name: 'views.md',
|
||||
}],
|
||||
}, {
|
||||
type: 'file',
|
||||
name: 'views.md',
|
||||
}]
|
||||
},
|
||||
]
|
||||
|
||||
describe('Tree', () => {
|
||||
it('should mount correctly', () => {
|
||||
@@ -45,29 +57,29 @@ describe('Tree', () => {
|
||||
<Tree.File name="header.js" />
|
||||
</Tree.Folder>
|
||||
<Tree.File name="readme.md" />
|
||||
</Tree>
|
||||
</Tree>,
|
||||
)
|
||||
expect(<Tree.File name="package.json" />).toMatchSnapshot()
|
||||
expect(<Tree.Folder name="components" />).toMatchSnapshot()
|
||||
expect(wrapper).toMatchSnapshot()
|
||||
expect(() => wrapper.unmount()).not.toThrow()
|
||||
})
|
||||
|
||||
|
||||
it('should show extra messages', () => {
|
||||
const files = mockFiles.map(item => ({ ...item, extra: 'extra' }))
|
||||
const files = mockFiles.map((item) => ({ ...item, extra: 'extra' }))
|
||||
const wrapper = mount(<Tree value={files} />)
|
||||
const firstName = wrapper.find('.name').at(0)
|
||||
expect(firstName.text()).toContain('extra')
|
||||
expect(() => wrapper.unmount()).not.toThrow()
|
||||
})
|
||||
|
||||
|
||||
it('should trigger event when file clicked', () => {
|
||||
const callback = jest.fn()
|
||||
const wrapper = mount(<Tree value={mockFiles} onClick={callback} />)
|
||||
wrapper.find('.file').at(0).simulate('click', nativeEvent)
|
||||
expect(callback).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
|
||||
it('should be work when value is empty', () => {
|
||||
const wrapper = mount(<Tree value={[]} />)
|
||||
expect(() => wrapper.unmount()).not.toThrow()
|
||||
|
||||
@@ -15,13 +15,19 @@ const defaultProps = {
|
||||
|
||||
export type TreeFileIconProps = Props & typeof defaultProps
|
||||
|
||||
const TreeFileIcon: React.FC<TreeFileIconProps> = ({
|
||||
color, width, height
|
||||
}) => {
|
||||
const TreeFileIcon: React.FC<TreeFileIconProps> = ({ color, width, height }) => {
|
||||
const theme = useTheme()
|
||||
return (
|
||||
<svg viewBox="0 0 24 24" width={width} height={height} stroke="currentColor" strokeWidth="1" strokeLinecap="round"
|
||||
strokeLinejoin="round" fill="none" shapeRendering="geometricPrecision">
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
width={width}
|
||||
height={height}
|
||||
stroke="currentColor"
|
||||
strokeWidth="1"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
shapeRendering="geometricPrecision">
|
||||
<path d="M13 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V9z" />
|
||||
<path d="M13 2v7h7" />
|
||||
<style jsx>{`
|
||||
|
||||
@@ -24,7 +24,12 @@ type NativeAttrs = Omit<React.HTMLAttributes<any>, keyof Props>
|
||||
export type TreeFileProps = Props & typeof defaultProps & NativeAttrs
|
||||
|
||||
const TreeFile: React.FC<React.PropsWithChildren<TreeFileProps>> = ({
|
||||
name, parentPath, level, extra, className, ...props
|
||||
name,
|
||||
parentPath,
|
||||
level,
|
||||
extra,
|
||||
className,
|
||||
...props
|
||||
}) => {
|
||||
const theme = useTheme()
|
||||
const { onFileClick } = useTreeContext()
|
||||
@@ -38,8 +43,13 @@ const TreeFile: React.FC<React.PropsWithChildren<TreeFileProps>> = ({
|
||||
<div className={`file ${className}`} onClick={clickHandler} {...props}>
|
||||
<div className="names">
|
||||
<TreeIndents count={level} />
|
||||
<span className="icon"><TreeFileIcon /></span>
|
||||
<span className="name">{name}{extra && <span className="extra">{extra}</span>}</span>
|
||||
<span className="icon">
|
||||
<TreeFileIcon />
|
||||
</span>
|
||||
<span className="name">
|
||||
{name}
|
||||
{extra && <span className="extra">{extra}</span>}
|
||||
</span>
|
||||
</div>
|
||||
<style jsx>{`
|
||||
.file {
|
||||
@@ -48,14 +58,14 @@ const TreeFile: React.FC<React.PropsWithChildren<TreeFileProps>> = ({
|
||||
user-select: none;
|
||||
margin-left: calc(1.875rem * ${level});
|
||||
}
|
||||
|
||||
|
||||
.names {
|
||||
display: flex;
|
||||
height: 1.75rem;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
||||
.names > :global(.indent) {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
@@ -65,31 +75,31 @@ const TreeFile: React.FC<React.PropsWithChildren<TreeFileProps>> = ({
|
||||
background-color: ${theme.palette.accents_2};
|
||||
margin-left: -1px;
|
||||
}
|
||||
|
||||
|
||||
.icon {
|
||||
width: 1.5rem;
|
||||
height: 100%;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
margin-right: .5rem;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
|
||||
.name {
|
||||
transition: opacity 100ms ease 0ms;
|
||||
color: ${theme.palette.accents_8};
|
||||
white-space: nowrap;
|
||||
font-size: .875rem;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
|
||||
.extra {
|
||||
font-size: .75rem;
|
||||
font-size: 0.75rem;
|
||||
align-self: baseline;
|
||||
padding-left: 4px;
|
||||
color: ${theme.palette.accents_5};
|
||||
}
|
||||
|
||||
|
||||
.name:hover {
|
||||
opacity: .7;
|
||||
opacity: 0.7;
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
|
||||
@@ -15,15 +15,20 @@ const defaultProps = {
|
||||
|
||||
export type TreeFolderIconProps = Props & typeof defaultProps
|
||||
|
||||
const TreeFolderIcon: React.FC<TreeFolderIconProps> = ({
|
||||
color, width, height,
|
||||
}) => {
|
||||
const TreeFolderIcon: React.FC<TreeFolderIconProps> = ({ color, width, height }) => {
|
||||
const theme = useTheme()
|
||||
return (
|
||||
<svg viewBox="0 0 24 24" width={width} height={height} stroke="currentColor" strokeWidth="1" strokeLinecap="round"
|
||||
strokeLinejoin="round" fill="none" shapeRendering="geometricPrecision">
|
||||
<path
|
||||
d="M2.707 7.454V5.62C2.707 4.725 3.469 4 4.409 4h4.843c.451 0 .884.17 1.204.474l.49.467c.126.12.296.186.473.186h8.399c.94 0 1.55.695 1.55 1.59v.737m-18.661 0h-.354a.344.344 0 00-.353.35l.508 11.587c.015.34.31.609.668.609h17.283c.358 0 .652-.269.667-.61L22 7.805a.344.344 0 00-.353-.35h-.278m-18.662 0h18.662" />
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
width={width}
|
||||
height={height}
|
||||
stroke="currentColor"
|
||||
strokeWidth="1"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
shapeRendering="geometricPrecision">
|
||||
<path d="M2.707 7.454V5.62C2.707 4.725 3.469 4 4.409 4h4.843c.451 0 .884.17 1.204.474l.49.467c.126.12.296.186.473.186h8.399c.94 0 1.55.695 1.55 1.59v.737m-18.661 0h-.354a.344.344 0 00-.353.35l.508 11.587c.015.34.31.609.668.609h17.283c.358 0 .652-.269.667-.61L22 7.805a.344.344 0 00-.353-.35h-.278m-18.662 0h18.662" />
|
||||
<style jsx>{`
|
||||
svg {
|
||||
color: ${color || theme.palette.accents_8};
|
||||
|
||||
@@ -28,7 +28,13 @@ type NativeAttrs = Omit<React.HTMLAttributes<any>, keyof Props>
|
||||
export type TreeFolderProps = Props & typeof defaultProps & NativeAttrs
|
||||
|
||||
const TreeFolder: React.FC<React.PropsWithChildren<TreeFolderProps>> = ({
|
||||
name, children, parentPath, level: parentLevel, extra, className, ...props
|
||||
name,
|
||||
children,
|
||||
parentPath,
|
||||
level: parentLevel,
|
||||
extra,
|
||||
className,
|
||||
...props
|
||||
}) => {
|
||||
const theme = useTheme()
|
||||
const { initialExpand, isImperative } = useTreeContext()
|
||||
@@ -46,19 +52,28 @@ const TreeFolder: React.FC<React.PropsWithChildren<TreeFolderProps>> = ({
|
||||
},
|
||||
[TreeFolder, TreeFile],
|
||||
)
|
||||
|
||||
|
||||
const sortedChildren = isImperative ? nextChildren : sortChildren(nextChildren, TreeFolder)
|
||||
|
||||
return (
|
||||
<div className={`folder ${className}`} onClick={clickHandler} {...props}>
|
||||
<div className="names">
|
||||
<TreeIndents count={parentLevel} />
|
||||
<span className="status"><TreeStatusIcon active={expanded} /></span>
|
||||
<span className="icon"><TreeFolderIcon /></span>
|
||||
<span className="name">{name}{extra && <span className="extra">{extra}</span>}</span>
|
||||
<span className="status">
|
||||
<TreeStatusIcon active={expanded} />
|
||||
</span>
|
||||
<span className="icon">
|
||||
<TreeFolderIcon />
|
||||
</span>
|
||||
<span className="name">
|
||||
{name}
|
||||
{extra && <span className="extra">{extra}</span>}
|
||||
</span>
|
||||
</div>
|
||||
<Expand isExpanded={expanded}>
|
||||
<div className="content" onClick={stopPropagation}>{sortedChildren}</div>
|
||||
<div className="content" onClick={stopPropagation}>
|
||||
{sortedChildren}
|
||||
</div>
|
||||
</Expand>
|
||||
|
||||
<style jsx>{`
|
||||
@@ -67,7 +82,7 @@ const TreeFolder: React.FC<React.PropsWithChildren<TreeFolderProps>> = ({
|
||||
line-height: 1;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
|
||||
.names {
|
||||
display: flex;
|
||||
height: 1.75rem;
|
||||
@@ -75,7 +90,7 @@ const TreeFolder: React.FC<React.PropsWithChildren<TreeFolderProps>> = ({
|
||||
margin-left: calc(1.875rem * ${parentLevel});
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
||||
.names > :global(.indent) {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
@@ -85,48 +100,49 @@ const TreeFolder: React.FC<React.PropsWithChildren<TreeFolderProps>> = ({
|
||||
background-color: ${theme.palette.accents_2};
|
||||
margin-left: -1px;
|
||||
}
|
||||
|
||||
|
||||
.status {
|
||||
position: absolute;
|
||||
left: calc(-1.125rem);
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
width: .875rem;
|
||||
height: .875rem;
|
||||
width: 0.875rem;
|
||||
height: 0.875rem;
|
||||
z-index: 10;
|
||||
background-color: ${theme.palette.background};
|
||||
}
|
||||
|
||||
|
||||
.icon {
|
||||
width: 1.5rem;
|
||||
height: 100%;
|
||||
margin-right: .5rem;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.status, .icon {
|
||||
|
||||
.status,
|
||||
.icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
|
||||
.name {
|
||||
transition: opacity 100ms ease 0ms;
|
||||
color: ${theme.palette.accents_8};
|
||||
white-space: nowrap;
|
||||
font-size: .875rem;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
|
||||
.extra {
|
||||
font-size: .75rem;
|
||||
font-size: 0.75rem;
|
||||
align-self: baseline;
|
||||
padding-left: 4px;
|
||||
color: ${theme.palette.accents_5};
|
||||
}
|
||||
|
||||
|
||||
.name:hover {
|
||||
opacity: .7;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
|
||||
.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -2,14 +2,13 @@ import React, { ReactNode } from 'react'
|
||||
|
||||
export const sortChildren = (
|
||||
children: ReactNode | undefined,
|
||||
folderComponentType: React.ElementType
|
||||
folderComponentType: React.ElementType,
|
||||
) => {
|
||||
return React.Children.toArray(children)
|
||||
.sort((a, b) => {
|
||||
if (!React.isValidElement(a) || !React.isValidElement(b)) return 0
|
||||
if (a.type !== b.type) return a.type !== folderComponentType ? 1 : -1
|
||||
return `${a.props.name}`.charCodeAt(0) - `${b.props.name}`.charCodeAt(0)
|
||||
})
|
||||
return React.Children.toArray(children).sort((a, b) => {
|
||||
if (!React.isValidElement(a) || !React.isValidElement(b)) return 0
|
||||
if (a.type !== b.type) return a.type !== folderComponentType ? 1 : -1
|
||||
return `${a.props.name}`.charCodeAt(0) - `${b.props.name}`.charCodeAt(0)
|
||||
})
|
||||
}
|
||||
|
||||
export const makeChildPath = (name: string, parentPath?: string) => {
|
||||
@@ -21,4 +20,3 @@ export const stopPropagation = (event: React.MouseEvent) => {
|
||||
event.stopPropagation()
|
||||
event.nativeEvent.stopImmediatePropagation()
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ const TreeIndents: React.FC<Props> = ({ count }) => {
|
||||
<span className="indent" key={`indent-${index}`}>
|
||||
<style jsx>{`
|
||||
span.indent {
|
||||
left: calc(-1.875rem * ${index + 1} + .75rem);
|
||||
left: calc(-1.875rem * ${index + 1} + 0.75rem);
|
||||
}
|
||||
`}</style>
|
||||
</span>
|
||||
|
||||
@@ -17,17 +17,23 @@ const defaultProps = {
|
||||
|
||||
export type TreeStatusIconProps = Props & typeof defaultProps
|
||||
|
||||
const TreeStatusIcon: React.FC<TreeStatusIconProps> = ({
|
||||
color, width, height, active,
|
||||
}) => {
|
||||
const TreeStatusIcon: React.FC<TreeStatusIconProps> = ({ color, width, height, active }) => {
|
||||
const theme = useTheme()
|
||||
return (
|
||||
<svg viewBox="0 0 24 24" width={width} height={height} stroke="currentColor" strokeWidth="1.5" strokeLinecap="round"
|
||||
strokeLinejoin="round" fill="none" shapeRendering="geometricPrecision">
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
width={width}
|
||||
height={height}
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
fill="none"
|
||||
shapeRendering="geometricPrecision">
|
||||
<rect x="3" y="3" width="18" height="18" rx="2" ry="2" />
|
||||
{!active && <path d="M12 8v8" />}
|
||||
<path d="M8 12h8" />
|
||||
|
||||
|
||||
<style jsx>{`
|
||||
svg {
|
||||
color: ${color || theme.palette.accents_8};
|
||||
|
||||
@@ -5,10 +5,7 @@ import { TreeContext } from './tree-context'
|
||||
import { tuple } from '../utils/prop-types'
|
||||
import { sortChildren } from '../file-tree/tree-help'
|
||||
|
||||
const FileTreeValueType = tuple(
|
||||
'directory',
|
||||
'file',
|
||||
)
|
||||
const FileTreeValueType = tuple('directory', 'file')
|
||||
|
||||
const directoryType = FileTreeValueType[0]
|
||||
|
||||
@@ -39,33 +36,42 @@ const makeChildren = (value: Array<FileTreeValue> = []) => {
|
||||
return value
|
||||
.sort((a, b) => {
|
||||
if (a.type !== b.type) return a.type !== directoryType ? 1 : -1
|
||||
|
||||
|
||||
return `${a.name}`.charCodeAt(0) - `${b.name}`.charCodeAt(0)
|
||||
})
|
||||
.map((item, index) => {
|
||||
if (item.type === directoryType) return (
|
||||
<TreeFolder name={item.name} extra={item.extra} key={`folder-${item.name}-${index}`}>
|
||||
{makeChildren(item.files)}
|
||||
</TreeFolder>
|
||||
)
|
||||
if (item.type === directoryType)
|
||||
return (
|
||||
<TreeFolder name={item.name} extra={item.extra} key={`folder-${item.name}-${index}`}>
|
||||
{makeChildren(item.files)}
|
||||
</TreeFolder>
|
||||
)
|
||||
return <TreeFile name={item.name} extra={item.extra} key={`file-${item.name}-${index}`} />
|
||||
})
|
||||
}
|
||||
|
||||
const Tree: React.FC<React.PropsWithChildren<TreeProps>> = ({
|
||||
children, onClick, initialExpand, value, className, ...props
|
||||
children,
|
||||
onClick,
|
||||
initialExpand,
|
||||
value,
|
||||
className,
|
||||
...props
|
||||
}) => {
|
||||
const isImperative = Boolean(value && value.length > 0)
|
||||
const onFileClick = (path: string) => {
|
||||
onClick && onClick(path)
|
||||
}
|
||||
|
||||
const initialValue = useMemo(() => ({
|
||||
onFileClick,
|
||||
initialExpand,
|
||||
isImperative,
|
||||
}), [initialExpand])
|
||||
|
||||
const initialValue = useMemo(
|
||||
() => ({
|
||||
onFileClick,
|
||||
initialExpand,
|
||||
isImperative,
|
||||
}),
|
||||
[initialExpand],
|
||||
)
|
||||
|
||||
const customChildren = isImperative ? makeChildren(value) : sortChildren(children, TreeFolder)
|
||||
|
||||
return (
|
||||
@@ -73,10 +79,10 @@ const Tree: React.FC<React.PropsWithChildren<TreeProps>> = ({
|
||||
<div className={`tree ${className}`} {...props}>
|
||||
{customChildren}
|
||||
<style jsx>{`
|
||||
.tree {
|
||||
padding-left: 1.625rem;
|
||||
}
|
||||
`}</style>
|
||||
.tree {
|
||||
padding-left: 1.625rem;
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
</TreeContext.Provider>
|
||||
)
|
||||
@@ -87,7 +93,9 @@ type TreeComponent<P = {}> = React.FC<P> & {
|
||||
Folder: typeof TreeFolder
|
||||
}
|
||||
|
||||
type ComponentProps = Partial<typeof defaultProps> & Omit<Props, keyof typeof defaultProps> & NativeAttrs
|
||||
type ComponentProps = Partial<typeof defaultProps> &
|
||||
Omit<Props, keyof typeof defaultProps> &
|
||||
NativeAttrs
|
||||
|
||||
Tree.defaultProps = defaultProps
|
||||
|
||||
|
||||
Reference in New Issue
Block a user