-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
16 changed files
with
580 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export const COMPONENT_NAME = 'FInputFile'; | ||
|
||
export const COMPONENT_NAME_DRAGGER = `${COMPONENT_NAME}Dragger`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { withInstall } from '../_util/withInstall'; | ||
import { type SFCWithInstall } from '../_util/interface'; | ||
import InputFile from './inputFile'; | ||
import InputFileDragger from './inputFileDragger'; | ||
|
||
export { inputFileProps, type InputFileProps } from './props'; | ||
|
||
type InputFileType = SFCWithInstall<typeof InputFile>; | ||
export const FInputFile = withInstall<InputFileType>( | ||
InputFile as InputFileType, | ||
); | ||
|
||
export { inputFileDraggerProps, type InputFileDraggerProps } from './props'; | ||
type InputFileDraggerType = SFCWithInstall<typeof InputFileDragger>; | ||
export const FInputFileDragger = withInstall<InputFileDraggerType>( | ||
InputFileDragger as InputFileDraggerType, | ||
); | ||
|
||
export default FInputFile; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import { defineComponent, type VNodeChild, type StyleValue } from 'vue'; | ||
import { useTheme } from '../_theme/useTheme'; | ||
import { CHANGE_EVENT, UPDATE_MODEL_EVENT } from '../_util/constants'; | ||
import getPrefixCls from '../_util/getPrefixCls'; | ||
import Button from '../button'; | ||
import { UploadOutlined } from '../icon'; | ||
import { COMPONENT_NAME } from './const'; | ||
import { type InputFileSlots, inputFileProps } from './props'; | ||
import { useInputFile } from './useInputFile'; | ||
|
||
const prefixCls = getPrefixCls('input-file'); | ||
const cls = (appendClass: string): string => `${prefixCls}-${appendClass}`; | ||
|
||
const InputFile = defineComponent({ | ||
name: COMPONENT_NAME, | ||
props: inputFileProps, | ||
emits: [UPDATE_MODEL_EVENT, CHANGE_EVENT], | ||
slots: Object as InputFileSlots, | ||
setup: (props, { emit, slots, attrs }) => { | ||
useTheme(); | ||
|
||
const { | ||
currentFiles, | ||
inputRef, | ||
disabled, | ||
multiple, | ||
acceptStr, | ||
openFileExplorer, | ||
handleInputFileChange, | ||
} = useInputFile(props, emit); | ||
|
||
const renderTrigger = (): VNodeChild => { | ||
if (slots.default) { | ||
return slots.default({}); | ||
} | ||
return ( | ||
<Button | ||
class={cls('trigger-button')} | ||
disabled={disabled.value} | ||
v-slots={{ icon: () => <UploadOutlined /> }} | ||
> | ||
选择文件 | ||
</Button> | ||
); | ||
}; | ||
|
||
const renderFileList = (files: File[]): VNodeChild => { | ||
if (files.length === 0) return null; | ||
|
||
if (slots.fileList) { | ||
return slots.fileList({ files }); | ||
} | ||
|
||
return files.length > 1 ? `${files.length} 个文件` : files[0].name; | ||
}; | ||
|
||
return () => ( | ||
<div class={prefixCls}> | ||
<div | ||
class={cls('visible-content')} | ||
style={attrs.style as StyleValue} | ||
> | ||
<div class={cls('trigger')} onClick={openFileExplorer}> | ||
{renderTrigger()} | ||
</div> | ||
<div class={cls('file-list')}> | ||
{renderFileList(currentFiles.value)} | ||
</div> | ||
</div> | ||
<input | ||
ref={inputRef} | ||
class={cls('input')} | ||
type={'file'} | ||
accept={acceptStr.value} | ||
multiple={multiple.value} | ||
onChange={handleInputFileChange} | ||
onClick={(e) => e.stopPropagation()} | ||
/> | ||
</div> | ||
); | ||
}, | ||
}); | ||
|
||
export default InputFile; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
import { defineComponent, type StyleValue, type VNodeChild } from 'vue'; | ||
import { useTheme } from '../_theme/useTheme'; | ||
import { CHANGE_EVENT, UPDATE_MODEL_EVENT } from '../_util/constants'; | ||
import getPrefixCls from '../_util/getPrefixCls'; | ||
import Message from '../message'; | ||
import { useLocale } from '../config-provider/useLocale'; | ||
import { COMPONENT_NAME_DRAGGER } from './const'; | ||
import { type InputFileSlots, inputFileDraggerProps } from './props'; | ||
import { useInputFile } from './useInputFile'; | ||
import { useFileDrop } from './useFileDrop'; | ||
|
||
const prefixCls = getPrefixCls('input-file-dragger'); | ||
const cls = (appendClass: string): string => `${prefixCls}-${appendClass}`; | ||
|
||
const InputFileDragger = defineComponent({ | ||
name: COMPONENT_NAME_DRAGGER, | ||
props: inputFileDraggerProps, | ||
emits: [UPDATE_MODEL_EVENT, CHANGE_EVENT], | ||
slots: Object as InputFileSlots, | ||
setup: (props, { emit, slots, attrs }) => { | ||
useTheme(); | ||
|
||
const { t } = useLocale(); | ||
|
||
const { | ||
currentFiles, | ||
updateCurrentFiles, | ||
inputRef, | ||
disabled, | ||
multiple, | ||
accept, | ||
acceptStr, | ||
openFileExplorer, | ||
handleInputFileChange, | ||
} = useInputFile(props, emit); | ||
|
||
const handleFileTypeInvalid = (files: File[]): void => { | ||
if (!props.onFileTypeInvalid) { | ||
Message.error(t('upload.fileTypeInvalidTip')); | ||
} | ||
props.onFileTypeInvalid(files); | ||
}; | ||
|
||
const { isHovering, handleEnter, handleLeave, handleOver, handleDrop } = | ||
useFileDrop({ | ||
disabled, | ||
multiple, | ||
accept, | ||
afterDrop: (files) => { | ||
updateCurrentFiles(files); | ||
emit(CHANGE_EVENT, files); | ||
}, | ||
onFileTypeInvalid: handleFileTypeInvalid, | ||
}); | ||
|
||
const renderFileList = (files: File[]): VNodeChild => { | ||
if (files.length === 0) return null; | ||
|
||
if (slots.fileList) { | ||
return slots.fileList({ files }); | ||
} | ||
|
||
return files.length > 1 ? `${files.length} 个文件` : files[0].name; | ||
}; | ||
|
||
return () => ( | ||
<div class={prefixCls}> | ||
<div | ||
class={cls('visible-content')} | ||
style={attrs.style as StyleValue} | ||
> | ||
<div | ||
class={[ | ||
cls('droppable'), | ||
isHovering.value && 'is-hovering', | ||
disabled.value && 'is-disabled', | ||
]} | ||
onDragenter={handleEnter} | ||
onDragleave={handleLeave} | ||
onDrop={handleDrop} | ||
onDragover={handleOver} | ||
onClick={openFileExplorer} | ||
> | ||
{slots.default?.({})} | ||
</div> | ||
<div class={cls('file-list')}> | ||
{renderFileList(currentFiles.value)} | ||
</div> | ||
</div> | ||
<input | ||
ref={inputRef} | ||
class={cls('input')} | ||
type={'file'} | ||
accept={acceptStr.value} | ||
multiple={multiple.value} | ||
onChange={handleInputFileChange} | ||
onClick={(e) => e.stopPropagation()} | ||
/> | ||
</div> | ||
); | ||
}, | ||
}); | ||
|
||
export default InputFileDragger; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import { | ||
type PropType, | ||
type ComponentObjectPropsOptions, | ||
type SlotsType, | ||
} from 'vue'; | ||
import { CHANGE_EVENT, UPDATE_MODEL_EVENT } from '../_util/constants'; | ||
import { | ||
type ComponentEmit, | ||
type ExtractPublicPropTypes, | ||
} from '../_util/interface'; | ||
|
||
const commonProps = { | ||
modelValue: { | ||
type: Array as PropType<File[]>, | ||
default: (): File[] => [], | ||
}, | ||
accept: { | ||
type: Array as PropType<string[]>, | ||
default: (): string[] => [], | ||
}, | ||
disabled: { | ||
type: Boolean, | ||
default: false, | ||
}, | ||
multiple: { | ||
type: Boolean, | ||
default: false, | ||
}, | ||
} as const satisfies ComponentObjectPropsOptions; | ||
|
||
// ------ Default Props ------ | ||
|
||
export const inputFileProps = { | ||
...commonProps, | ||
} as const satisfies ComponentObjectPropsOptions; | ||
|
||
export type InputFileProps = ExtractPublicPropTypes<typeof inputFileProps>; | ||
|
||
// ------ Dragger Props ------ | ||
|
||
export const inputFileDraggerProps = { | ||
...commonProps, | ||
onFileTypeInvalid: { | ||
type: Function as PropType<(files: File[]) => void>, | ||
}, | ||
} as const satisfies ComponentObjectPropsOptions; | ||
|
||
export type InputFileDraggerProps = ExtractPublicPropTypes< | ||
typeof inputFileDraggerProps | ||
>; | ||
|
||
// ------ Emit ------ | ||
export const EMIT_EVENTS = [UPDATE_MODEL_EVENT, CHANGE_EVENT] as const; | ||
export type InputFileEmit = ComponentEmit<typeof EMIT_EVENTS>; | ||
|
||
// ------ Slots ------ | ||
export type InputFileSlotsParams = { | ||
default: Record<string, never>; | ||
fileList: { | ||
files: File[]; | ||
}; | ||
}; | ||
|
||
export type InputFileSlots = SlotsType<InputFileSlotsParams>; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
@import '../../style/themes/index'; | ||
@import '../../style/mixins/index'; | ||
|
||
@input-file: ~'@{cls-prefix}-input-file'; | ||
@input-file-dragger: ~'@{cls-prefix}-input-file-dragger'; | ||
|
||
.@{input-file}, .@{input-file-dragger} { | ||
&-input { | ||
display: none; | ||
} | ||
|
||
&-file-list { | ||
.text(); | ||
color: var(--f-sub-head-color); | ||
} | ||
} | ||
|
||
.@{input-file} { | ||
.@{input-file}-visible-content { | ||
display: flex; | ||
align-items: center; | ||
|
||
.@{input-file}-trigger { | ||
cursor: pointer; | ||
} | ||
|
||
.@{input-file}-file-list { | ||
margin-left: var(--f-padding-xsmall); | ||
} | ||
} | ||
} | ||
|
||
.@{input-file-dragger} { | ||
width: 100%; | ||
|
||
.@{input-file-dragger}-visible-content { | ||
|
||
.@{input-file-dragger}-droppable { | ||
width: 100%; | ||
padding: var(--f-padding-middle); | ||
text-align: center; | ||
background-color: var(--f-component-bg-color); | ||
border: var(--f-border-width-base) dashed var(--f-border-color-base); | ||
border-radius: var(--f-border-radius-base); | ||
cursor: pointer; | ||
transition: border-color @animation-duration-slow @ease-base-in; | ||
|
||
&:hover, &.is-hovering{ | ||
border-color: var(--f-primary-color); | ||
} | ||
|
||
&.is-disabled { | ||
color: var(--f-text-color-disabled); | ||
border-color: var(--f-border-color-base); | ||
cursor: not-allowed; | ||
} | ||
} | ||
|
||
.@{input-file-dragger}-file-list { | ||
margin-top: var(--f-padding-xsmall); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
import '../../style'; | ||
import './index.less'; |
Oops, something went wrong.