Skip to content

Commit

Permalink
feat: add nativeElement & openPhoto to imageUploader ant-design#6289
Browse files Browse the repository at this point in the history
  • Loading branch information
19Qingfeng committed Aug 11, 2023
1 parent 67dc672 commit 893b789
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 8 deletions.
56 changes: 53 additions & 3 deletions src/components/image-uploader/demos/demo2.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import React, { FC, useState } from 'react'
import React, { FC, useRef, useState } from 'react'
import { DemoBlock } from 'demos'
import { ImageUploadItem } from 'antd-mobile/es/components/image-uploader'
import { ImageUploader } from 'antd-mobile'
import {
ImageUploadItem,
ImageUploaderInstance,
} from 'antd-mobile/es/components/image-uploader'
import { ImageUploader, Button } from 'antd-mobile'
import { PictureOutline } from 'antd-mobile-icons'

import { demoSrc, mockUpload } from './utils'
Expand Down Expand Up @@ -74,6 +77,49 @@ const CustomUploadButton: FC = () => {
)
}

// 手动吊起相册
const ManualOpenPhoto: FC = () => {
const imageRef = useRef<ImageUploaderInstance>(null)
const [fileList, setFileList] = useState<ImageUploadItem[]>([
{
url: demoSrc,
},
])

const onOpen = () => {
imageRef.current?.openPhoto()
}

return (
<>
<ImageUploader
ref={imageRef}
value={fileList}
onChange={setFileList}
upload={mockUpload}
>
<div
style={{
width: 80,
height: 80,
borderRadius: 40,
backgroundColor: '#f5f5f5',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
color: '#999999',
}}
>
<PictureOutline style={{ fontSize: 32 }} />
</div>
</ImageUploader>
<Button onClick={() => onOpen()} style={{ margin: 6 }}>
手动吊起相册
</Button>
</>
)
}

export default () => {
return (
<>
Expand All @@ -88,6 +134,10 @@ export default () => {
<DemoBlock title='自定义上传按钮'>
<CustomUploadButton />
</DemoBlock>

<DemoBlock title='手动吊起相册'>
<ManualOpenPhoto />
</DemoBlock>
</>
)
}
28 changes: 25 additions & 3 deletions src/components/image-uploader/image-uploader.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React, {
FC,
forwardRef,
InputHTMLAttributes,
useRef,
useState,
CSSProperties,
useImperativeHandle,
} from 'react'
import { AddOutline, CloseOutline } from 'antd-mobile-icons'
import { mergeProps } from '../../utils/with-default-props'
Expand Down Expand Up @@ -69,6 +70,11 @@ export type ImageUploaderProps = {
) => React.ReactNode
} & NativeProps<'--cell-size' | '--gap' | '--gap-vertical' | '--gap-horizontal'>

export interface ImageUploaderInstance {
openPhoto: () => void
nativeElement: HTMLInputElement | null
}

const classPrefix = `adm-image-uploader`

const defaultProps = {
Expand All @@ -85,7 +91,10 @@ const defaultProps = {
imageFit: 'cover',
}

export const ImageUploader: FC<ImageUploaderProps> = p => {
export const ImageUploader = forwardRef<
ImageUploaderInstance,
ImageUploaderProps
>((p, ref) => {
const { locale } = useConfig()
const props = mergeProps(defaultProps, p)
const { columns } = props
Expand All @@ -99,6 +108,8 @@ export const ImageUploader: FC<ImageUploaderProps> = p => {
const gapMeasureRef = useRef<HTMLDivElement>(null)
const [cellSize, setCellSize] = useState<number>(80)

const inputRef = useRef<HTMLInputElement>(null)

useIsomorphicLayoutEffect(() => {
const gapMeasure = gapMeasureRef.current
if (columns && containerSize && gapMeasure) {
Expand Down Expand Up @@ -153,6 +164,7 @@ export const ImageUploader: FC<ImageUploaderProps> = p => {

async function onChange(e: React.ChangeEvent<HTMLInputElement>) {
e.persist()
// 这里支持一个 Ref
const { files: rawFiles } = e.target
if (!rawFiles) return
let files = [].slice.call(rawFiles) as File[]
Expand Down Expand Up @@ -311,6 +323,7 @@ export const ImageUploader: FC<ImageUploaderProps> = p => {
)}
{!props.disableUpload && (
<input
ref={inputRef}
capture={props.capture}
accept={props.accept}
multiple={props.multiple}
Expand All @@ -324,6 +337,15 @@ export const ImageUploader: FC<ImageUploaderProps> = p => {
</>
)

useImperativeHandle(ref, () => {
return {
get nativeElement() {
return inputRef.current
},
openPhoto: () => inputRef.current?.click(),
}
})

return withNativeProps(
props,
<div className={classPrefix} ref={containerRef}>
Expand All @@ -339,4 +361,4 @@ export const ImageUploader: FC<ImageUploaderProps> = p => {
)}
</div>
)
}
})
7 changes: 7 additions & 0 deletions src/components/image-uploader/index.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@
| onUploadQueueChange | Triggered when the image upload queue changes | `(tasks: UploadTask[]) => void` |
| renderItem | Custom item of uploadList | `(originNode: React.ReactElement, file: ImageUploadItem, fileList: ImageUploadItem[] ) => React.ReactNode` | - |

### ImageInstance

| 属性 | 说明 | 类型 | 默认值 |
| ------------- | -------------------------- | ----------------- | ------ | --- |
| openPhoto | Manually lifting the album | `() => void` | - |
| nativeElement | native input element | `HTMLInputElement | null` | - |

### ImageUploadItem

| Name | Description | Type | Default |
Expand Down
1 change: 1 addition & 0 deletions src/components/image-uploader/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import './image-uploader.less'

export type {
ImageUploadItem,
ImageUploaderInstance,
ImageUploaderProps,
UploadTask,
} from './image-uploader'
Expand Down
7 changes: 7 additions & 0 deletions src/components/image-uploader/index.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@
| onUploadQueueChange | 图片上传队列变化时触发 | `(tasks: UploadTask[]) => void` | - |
| renderItem | 自定义上传列表项 | `(originNode: React.ReactElement, file: ImageUploadItem, fileList: ImageUploadItem[] ) => React.ReactNode` | - |

### ImageInstance

| 属性 | 说明 | 类型 | 默认值 |
| ------------- | -------------- | ----------------- | ------ | --- |
| openPhoto | 手动吊起相册 | `() => void` | - |
| nativeElement | 源生输入框节点 | `HTMLInputElement | null` | - |

### ImageUploadItem

| 属性 | 说明 | 类型 | 默认值 |
Expand Down
57 changes: 55 additions & 2 deletions src/components/image-uploader/tests/image-uploader.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from 'react'
import React, { useEffect, useRef, useState } from 'react'
import {
render,
testA11y,
Expand All @@ -11,8 +11,9 @@ import {
act,
waitForElementToBeRemoved,
} from 'testing'
import ImageUploader, { ImageUploadItem } from '..'
import ImageUploader, { ImageUploadItem, ImageUploaderInstance } from '..'
import Dialog from '../../dialog'
import Button from '../../button'

const classPrefix = `adm-image-uploader`

Expand Down Expand Up @@ -380,4 +381,56 @@ describe('ImageUploader', () => {
expect(fn).toBeCalledWith([{ id: 0, status: 'success' }])
expect(fn.mock.lastCall[0]).toMatchObject([])
})

test('Manually lifting the album', async () => {
const fn = jest.fn()
const openPhoto = jest.fn()

const Manually = (props: any) => {
const [fileList, setFileList] = useState<ImageUploadItem[]>([
{
url: demoSrc,
},
])

const imageRef = useRef<ImageUploaderInstance>(null)

const onOpen = () => {
Object.defineProperty(imageRef.current, 'openPhoto', {
value: () => {
openPhoto()
},
})
imageRef.current?.openPhoto()
}

useEffect(() => {
props.getNativeElement &&
props.getNativeElement(imageRef.current?.nativeElement?.type)
}, [])

return (
<>
<ImageUploader
ref={imageRef}
value={fileList}
onChange={setFileList}
upload={mockUpload}
{...props}
/>
<Button onClick={() => onOpen()}>Manually Upload</Button>
</>
)
}

const { getByText } = render(
<Manually upload={mockUpload} getNativeElement={fn} />
)

const button = getByText('Manually Upload')

fireEvent.click(button)
expect(openPhoto).toBeCalled()
expect(fn).toBeCalledWith('file')
})
})

0 comments on commit 893b789

Please sign in to comment.