生态产品多个设计器现已发布正式版

查看生态总览
跳转到内容

FileUpload 文件上传 ​

选择文件、拖放文件,并列出已选与已上传的文件。

用法 ​

投放区自身就是一个大按钮,隐藏输入是必备部件,缺少它无法选择文件

把文件拖到这里或者用下面的按钮挑一个

组件结构 ​

加粗的是必需部件。

data-scope="file-upload":root · label · dropzone · trigger · hidden-input · list · item · item-name · item-link · item-size-text · item-preview · item-progress · item-delete-trigger · clear-trigger

示例 ​

限制与拒收 ​

accept / maxFiles / maxFileSize 越界的当场被拒绝,file-reject 逐个报告理由

只收图片,最多 3 张单张不超过 512 KB
被拒:(暂无)

受控 ​

传入 files 后由宿主决定,组件自身不再落值,只发 files-change 报告意图

选进来的文件由外部数组保管
宿主持有 0 个文件

禁用 ​

disabled 把投放区、触发器与隐藏输入一并关停,拖拽进入也不再接收

当前不接受上传

预置列表 ​

defaultFiles 给出挂载时已存在的文件,之后列表照常由组件自行保管,删除与清空都照常

已经带了两份进来再拖几份也收,最多 4 份
合同正文.txt54 B
交付说明.md34 B

选择整个目录 ​

directory 使隐藏输入改为接收目录,选中目录下的文件一次性全部进入,数量上限要随之放开

挑一个目录,里面的文件全收
共 0 个文件

缩略图墙 ​

item-preview 是一个空方框,作者可放置任意内容;放入的图片会被裁为方格,一行排几张由外层网格决定

把图片拖进来,最多 6 张

作者的准入判定 ​

accept 与大小数量之外的规矩交给 validate:类型与大小通过之后逐个问它,返回拒绝码即拒收,拒收的文件带着这个码进 file-reject;这里同名文件只收最先到的一份

同名文件只收最先来的那份
同名挡下:(暂无)

上传生命周期 ​

提供一个 upload 实现后组件即为上传器:接收即开始上传(auto-upload 可关闭为手动),进度、成败与返回地址都在每条的传输快照中,失败可一键重试

拖进来或点击选择,收下即开传

试试选一个文件名带「坏」字的文件,看失败与重试。

列表项上的下载 ​

条目中放置什么由作者决定:一条普通的 a[download] 就是下载入口;需要自行接管时换为按钮,在处理器中自行获取

放几份文件进来,每条后面就带上下载口

服务器附件回显 ​

remote-files 承载编辑表单中已存在的附件:与本地文件同列渲染(allFiles 远程在前)、占用 max-files 名额,删除经 remote-files-change 由宿主落库

拖进来或点击选择
合同扫描件.pdf373 KB查看
报价单.xlsx50 KB查看

剩余名额与新选文件共享;删除服务器附件只改 remote-files,落库由宿主决定。

并发上限与取消 ​

max-concurrent-uploads 限定同时在传的份数,多出来的排队依次补上;cancelUpload 只中止传输、文件留在列表里,startUpload 让它重新开传

一次多选几份,同时只传两份

设计指引 ​

何时使用 ​

  • 需要用户提交文件的场景。
  • 需要预览、限制类型与大小,或选择整个目录。

何时不用 ​

  • 只展示已有附件、不允许新增时,使用列表。

特性 ​

  • 超出 maxFiles / maxFileSize / minFileSize 的文件立即被拒绝,onFileReject 逐个报告原因。
  • autoUpload 决定选择后立即上传还是等待提交。
  • remoteFiles 回显服务器上已有的附件,与本次新选的文件并列在同一个列表中。
  • validate 在类型与大小校验之后逐个判定,返回拒绝码即拒收,与内建原因一起进 onFileReject。
  • 焦点在组件里时可以直接粘贴文件(allowPaste,默认开启),与选择、投放走同一道校验。
  • 上传生命周期(完成、失败、取消)各有回调;maxConcurrentUploads 限定同时在传的份数,其余排队。
  • readOnly 时列表改不动(选择、拖放、粘贴、删除与清空都不收),已经开始的传输照常;required 时标题画星号,列表为空时文件输入带原生 required。
  • cancelUpload 中止传输但保留文件,startUpload 让取消或失败的文件重新开传;删除文件同样中止它的传输。
  • upload 返回 { id } 时,传完的文件转成服务器已有附件:从 files 移出、追加进 remoteFiles,表单值直接是附件记录。remoteFiles 受控时宿主写回含这个 id 的列表之后才移出。
  • 点标题只把焦点交给投放区(没写投放区时交给选择钮),不弹出选择框;label 的 for 仍指向隐藏输入,原生关联与必填提示照旧。禁用时投放区退出 Tab 序列,只读时留在 Tab 序列里,两者都报 aria-disabled、不收拖放与粘贴。
  • 不写结构时按标准结构铺出整套部件(Vue 不写默认插槽、React 不给 children、Web Components 不写部件或只写 root),三端出自同一个结构函数:label 给标题文字,接着是投放区(说明文字取 translations.dropzone)、表单影子与文件列表,clearable 时末尾带清空钮。投放区是唯一可聚焦的打开入口,不另铺选择钮;列表里 allFiles 每个文件一行(缩略图、文件名、大小、进度与删除钮),按 fileKey 认行,删掉中间一行时替身留在原处淡出。远程附件的 url 经安全判定(只放行 http、https、mailto、tel 与相对地址)后,文件名铺成链接 item-link,打开方式取 linkTarget(缺省当前页,_blank 时带 rel="noopener noreferrer");地址不安全时文件名是纯文字。只读时链接照常可聚焦、可打开,禁用时退出 Tab 序列。Web Components 里标题与投放区的内容可以写在宿主的直接子节点 slot="label"、slot="dropzone" 上接管。

组合 ​

最佳实践 ​

  • 在界面上说明允许的类型与大小上限,不等用户选择后才拒绝。
  • 拒绝时说明是哪个文件、原因是什么。

反模式 ​

  • 只在前端校验,不在后端校验。
  • 上传中不显示进度也不能取消。

API 参考 ​

产物 ​

层值
自定义元素<xh-file-upload>
Vue 组件XhFileUploadClearTrigger XhFileUploadDropzone XhFileUploadHiddenInput XhFileUploadItem XhFileUploadItemDeleteTrigger XhFileUploadItemLink XhFileUploadItemName XhFileUploadItemPreview XhFileUploadItemProgress XhFileUploadItemSizeText XhFileUploadLabel XhFileUploadList XhFileUploadRoot XhFileUploadTrigger
组合式函数useFileUpload
状态机fileUploadMachine
皮肤@xihan-ui/styles/file-upload.css

Props ​

属性类型必填说明
labelledboolean作者渲染了 label 部件时置真,由适配器统计而不是判断标题文字是否有值。 为假时可聚焦部件不把 label 的 id 写进 aria-labelledby:指向未渲染的 id 是无效引用,作者写在控件上的 aria-label 也会被它压住。
ariaLabelstring不显示出来的名字,写成 aria-label 落在与字段标签同一个部件上。 放进字段(字段接线)或渲染了 label 部件时名字以它们为准,aria-labelledby 盖过它。
acceptstring | string[]允许的类型,写法与原生 input 的 accept 一致: 接受 'image/*' 这类通配、'.png' 这类扩展名、'application/pdf' 这类精确 MIME, 逗号分隔的整串或数组两种形态均可(属性只能表达整串,数组需通过 property)。
maxFilesnumber最多保留的文件数,默认 1。提供 Infinity 即不限。
maxFileSizenumber单个文件的字节上限,默认不限。
minFileSizenumber单个文件的字节下限,默认 0(拦截 0 字节的空文件可设为 1)。
disabledboolean
invalidboolean校验失败标注;只作用于样式与 data-invalid,不阻断接收文件。
readOnlyboolean只读:列表改不动——选择、拖放、粘贴、删除与清空都不收,已经开始的传输照常进行。 投放区与三种按钮仍可聚焦,报 aria-disabled="true"。
requiredboolean必填:根与标题写 data-required(标题据此画星号);列表为空时文件输入带原生 required,拦下空表单的提交。 有文件时不带:选完文件输入就被清空,恒带 required 会把已经选了文件的表单也拦下。
namestring表单字段名;提供后隐藏输入才参与提交。
filesFile[]已选文件。提供即受控:cell 直读 prop,写入只发 onFilesChange 不落内部值。
defaultFilesFile[]
allowDropboolean是否接受拖拽投放,默认 true。关闭后投放区不再拦截默认行为,也不再输出 data-dragging。
allowPasteboolean是否接受粘贴,默认 true:焦点在组件里(投放区、选择钮、删除钮)时 Ctrl / Cmd+V 收下剪贴板里的文件, 与选择、投放走同一道校验。剪贴板里没有文件时不拦截,文字照常粘贴到别处。
validate(file: File, context: FileUploadValidateContext) => string | string[] | null | undefined作者自己的准入判定,在类型与大小校验通过之后、数量上限之前逐个调用:返回拒绝码(一个或一组)即拒收, 拒收的文件连同返回的码一起进 onFileReject,不占数量名额;返回 null / undefined / 空数组即放行。 只接受同步判定;要读图片尺寸之类的异步检查放进 upload,失败时抛错走 onUploadError。
maxConcurrentUploadsnumber同时在传的文件数上限,默认不限。到了上限的文件报 queued 排队,前面的传完、失败或被取消后按列表顺序补上。
directoryboolean选择目录而不是文件(隐藏输入带 webkitdirectory)。
capture'user' | 'environment'移动端直接调用摄像头 / 麦克风采集。
linkTargetstring附件链接(item-link)的打开方式,写到链接的 target 上;缺省在当前页打开。 写 _blank 时链接同时带 rel="noopener noreferrer"。
remoteFilesFileUploadRemoteFile[]服务器已有附件(编辑表单回显)。提供即受控:cell 直读 prop,删改只发 onRemoteFilesChange 不落内部值。条目计入 maxFiles 总量,与本地文件一起渲染。
defaultRemoteFilesFileUploadRemoteFile[]
upload(request: FileUploadRequest) => Promise<FileUploadResult | undefined | void> | FileUploadResult | undefined | void每个文件的传输实现。提供后组件才是上传器:接受的文件按 autoUpload 自动开始传输, 进度、成败与返回地址都记入该文件的传输快照。未提供时保持纯选择器。
autoUploadboolean接受后即自动开始传输,默认 true;关闭后由 api.startUpload 逐个开始。
translationsPartial<FileUploadTranslations>
onFilesChange(details: FileUploadFilesChangeDetails) => void列表变化意图回调;受控时是唯一出口,非受控时随内部写入一并通知。
onClear() => void用户按清空钮(clear-trigger)清掉了值;先发值变化,再发它。程序化的 clear() 不发。
onFileAccept(details: FileUploadFileAcceptDetails) => void本次接受了哪些文件。受控与否都发出:宿主据此发起上传。
onFileReject(details: FileUploadFileRejectDetails) => void本次拒绝了哪些文件及各自的原因。
onRemoteFilesChange(details: FileUploadRemoteFilesChangeDetails) => void远程附件列表变化意图回调;受控时是唯一出口,非受控时随内部写入一并通知。
onUploadComplete(details: FileUploadCompleteDetails) => void单个文件传输完成(upload 的 Promise 兑现)。
onUploadError(details: FileUploadErrorDetails) => void单个文件传输失败(upload 的 Promise 拒绝);中止不视为失败,不发出。
onUploadCancel(details: FileUploadCancelDetails) => void单个文件的传输被 cancelUpload 取消(文件留在列表里);删除文件时的中止不发出。

FileUploadRemoteFile ​

remoteFiles 的元素。

字段类型必填说明
idstring是稳定标识(通常是服务端主键),删除与去重都以它为准。
namestring是
sizenumber字节数;未提供时不显示大小。
typestringMIME 类型。
urlstring

事件 ​

自定义元素将载荷放在 detail;Vue 使用同名 emit。

事件载荷说明
files-changeFileUploadFilesChangeDetails列表变化;detail 为 { files: File[] }
clear``用户按清空钮(clear-trigger)清掉了值;先发值变化,再发它。程序化的 clear() 不发。
remote-files-changeFileUploadRemoteFilesChangeDetails远程附件列表变化;detail 为 { files: FileUploadRemoteFile[] }
upload-completeFileUploadCompleteDetails单个文件传输完成;detail 为 { file, url?, id? },带 id 时这个文件随后转入 remoteFiles
upload-errorFileUploadErrorDetails单个文件传输失败;detail 为 { file, error }
upload-cancelFileUploadCancelDetails单个文件的传输被 cancelUpload 取消(文件留在列表里);detail 为 { file }
file-acceptFileUploadFileAcceptDetails本次接受了哪些文件;detail 为 { files: File[] }
file-rejectFileUploadFileRejectDetails本次拒绝了哪些文件及各自的原因;detail 为 { files: { file, reasons }[] }

插槽 ​

仅列出带载荷的插槽。

Vue 组件插槽载荷说明
XhFileUploadRootdefaultFileUploadRootSlotProps
XhFileUploadRootlabel—
XhFileUploadRootdropzone—不写默认插槽时投放区里的内容;未写时取 translations.dropzone。

React 适配器 props ​

只列各组件自己声明的那些:继承自 ComponentPropsWithRef 的 DOM 属性不在其中,根组件上与上面 Props 表同名的也不重复列。Vue 的对应物是上面的插槽表。

React 组件属性类型必填说明
XhFileUploadItemfileFileUploadFile该行显示哪个文件(本地或远程附件)。
XhFileUploadItemindexnumber | string改用下标从 allFiles(远程在前、本地在后)中取文件,兼收字符串。
XhFileUploadRootlabelReactNode标题。不给 children 时铺 label 部件。
XhFileUploadRootdropzoneReactNode不给 children 时投放区里的内容;未写时取 translations.dropzone。
XhFileUploadRootclearableboolean不给 children 时列表之后带清空整份列表的按钮;给了 children 时放 clear-trigger 部件即可清空。
XhFileUploadRootchildrenSlotChildren<FileUploadRootSlotProps>

状态 ​

公开状态写入 data-state。

部件取值
itemuploadOf(file)?.status
item-progressupload?.status

以下名称仅用于内部状态机。

状态:idle · dragging

事件:FILES.SET · FILES.ADD · FILE.DELETE · FILES.CLEAR · PICKER.OPEN · DRAG.OVER · DRAG.LEAVE · DROP · PASTE · UPLOAD.CANCEL · UPLOAD.START · REMOTE.DELETE · FORM.RESET · PRESS.START · PRESS.END · LIST.TRACKED · PROGRESS.SETTLED

判据:canChange · canTransfer · canDrop · canPaste

connect API ​

getXxxProps() 返回对应部件的宿主属性。

成员类型说明
acceptedFilesFile[]
remoteFilesFileUploadRemoteFile[]服务器已有附件。
allFilesFileUploadFile[]渲染顺序的完整列表:远程在前、本地在后。
draggingboolean有内容正悬停在投放区上方。
disabledboolean
invalidboolean
readOnlyboolean
requiredboolean
emptyboolean没有任何文件。清空按钮据此写 data-empty,空列表据此显示占位。
maxFilesnumber生效的数量上限(已按默认值与非法值归一)。
translationsFileUploadTranslations合上作者覆盖后的文案。
fileKey(file: FileUploadFile) => string文件在列表里的稳定标识:本地文件取机器发的内部 id,远程附件取 remote:&lt;id&gt;。 同名同大小的两份本地文件标识不同;列表增删时据此认出哪一行还是那一行。
fileHref(file: FileUploadFile) => string | undefined文件可打开的地址:远程附件的 url 经安全判定(只放行 http、https、mailto、tel 与相对地址)后的结果; 本地文件、没有 url 或地址不安全时为 undefined,此时标准结构只铺纯文字的文件名。
getFileSizeText(file: FileUploadFile) => string字节数格式化为可读形式,供作者渲染 item-size-text;远程附件未报大小时为空串。
uploadOf(file: FileUploadFile) => FileUploadSnapshot | null该条目的传输快照:远程附件恒为 done;本地文件未配置 upload 时为 null, 已配置而尚未开始传输时为 idle。
startUpload(file: File) => void手动开始传输(autoUpload 关闭时)、失败或取消后重试;不在列表中或传输中的文件调用无效。
cancelUpload(file: File) => void取消这个文件的传输(在传或排队中),文件留在列表里、状态落 canceled;删除用 deleteFile。
setFiles(files: File[]) => void
addFiles(files: File[]) => void
deleteFile(file: FileUploadFile) => void本地文件按引用移除(传输中会中止),远程附件按 id 移除。
clear() => void清空整份列表(本地与远程一起)。
openFilePicker() => void
getRootProps() => T['element']
getLabelProps() => T['label']
getDropzoneProps() => T['element']
getTriggerProps() => T['button']
getHiddenInputProps() => T['input']
getListProps() => T['element']
getItemProps(props: FileUploadItemProps) => T['element']
getItemNameProps(props: FileUploadItemProps) => T['element']
getItemLinkProps(props: FileUploadItemProps) => T['element']附件链接:落在文件名里、指向 fileHref 的 <a>。地址不安全时不写 href;target 取 linkTarget,_blank 时带 rel="noopener noreferrer"。只读时照常可聚焦、可打开;禁用时退出 Tab 序列、报 aria-disabled,点了不跳转。
getItemSizeTextProps(props: FileUploadItemProps) => T['element']
getItemPreviewProps(props: FileUploadItemProps) => T['element']
getItemProgressProps(props: FileUploadItemProps) => T['element']该条目的传输进度条,纯装饰;进度比例写在私有槽上供皮肤计算宽度。
getItemDeleteTriggerProps(props: FileUploadItemProps) => T['button']
getClearTriggerProps() => T['button']

无障碍 ​

键盘 ​

规格出处:W3C APG

按键生效条件行为
Tab / Shift+Tabfocus outside / inside the component投放区、选择按钮、每条的删除按钮与清空按钮各占一个 Tab 位;禁用时投放区退出 Tab 序列,几个原生按钮带 disabled 本就不可聚焦
Enter / Spacefocus on dropzone打开系统文件选择框。投放区是 div,浏览器不会替它把这两个键合成成一次点击,连接层自己接管(并拦下空格滚屏)
Enter / Spacefocus on trigger打开系统文件选择框(原生 button 的默认激活)
Enter / Spacefocus on item-delete-trigger把这一条从列表里删掉(原生 button 的默认激活)
Enter / Spacefocus on clear-trigger清空整份列表(原生 button 的默认激活);列表为空时按钮照常在位、可聚焦,激活是空操作
Ctrl+V / Meta+Vfocus inside the component, not disabled, allowPaste收下剪贴板里的文件,与选择、投放走同一道校验;剪贴板里没有文件时不拦截,文字照常粘贴到别处
Enter / Spaceheld on trigger / item-delete-trigger / clear-trigger, not disabled按住期间该按钮投影 data-pressed,与指针 :active 同一副按压面;抬起或失焦撤下(选择钮打开系统文件框即失焦),删除钮随文件离开列表时一并撤下

ARIA ​

以下属性由 connect 生成。

部件属性值
dropzonearia-disabled'false' | 'true'
dropzonearia-invalid'true' | 'false'
dropzonearia-labelundefined | props.ariaLabel
dropzonearia-labelledbylabel 部件的 id dropzone 部件的 id | dropzone 部件的 id
dropzonerole'button'
triggeraria-disabled'true' | undefined
hidden-inputaria-labelledbylabel 部件的 id dropzone 部件的 id | dropzone 部件的 id
listrole'list'
itemrole'listitem'
item-linkaria-disabled'true' | undefined
item-previewaria-hidden'true'
item-progressaria-hidden'true'
item-delete-triggeraria-disabled'true' | undefined
item-delete-triggeraria-labellabel.deleteItem(file)
clear-triggeraria-disabled'true' | undefined
clear-triggeraria-labellabel.clearTrigger

样式参考 ​

皮肤 ​

@xihan-ui/styles/file-upload.css 按 [data-scope="file-upload"][data-part="root"] 部件选择器书写,发布产物以挂载类 .xh-scope-file-upload 代替其中的 data-scope(特异性相同),位于 xihan.components 层。覆盖样式使用 xihan.overrides,部件选择器照常可用。

forced-colors: active 下另有一套规则:颜色交给系统,边框与状态标记改用系统色关键字。

数据属性 ​

由 connect 生成;条件不成立时不输出无值属性。

部件属性值
rootdata-disabled''(条件成立时才出现)
rootdata-dragging''(条件成立时才出现)
rootdata-empty''(条件成立时才出现)
rootdata-invalid''(条件成立时才出现)
rootdata-readonly''(条件成立时才出现)
rootdata-required''(条件成立时才出现)
labeldata-disabled''(条件成立时才出现)
labeldata-required''(条件成立时才出现)
dropzonedata-disabled''(条件成立时才出现)
dropzonedata-dragging''(条件成立时才出现)
dropzonedata-invalid''(条件成立时才出现)
dropzonedata-readonly''(条件成立时才出现)
triggerdata-disabled''(条件成立时才出现)
triggerdata-pressed''(条件成立时才出现)
triggerdata-readonly''(条件成立时才出现)
triggerdata-xh-action-control''
triggerdata-xh-action-display'always'
triggerdata-xh-action-profile'text'
triggerdata-xh-action-size'md'
triggerdata-xh-action-variant'outline'
listdata-disabled''(条件成立时才出现)
listdata-empty''(条件成立时才出现)
listdata-instant''(条件成立时才出现)
itemdata-disabled''(条件成立时才出现)
itemdata-file-namefile.name
itemdata-file-sizeundefined | String(file.size) | String(file.size)
itemdata-remote''(条件成立时才出现)
itemdata-stateuploadOf(file)?.status
item-namedata-disabled''(条件成立时才出现)
item-linkdata-disabled''(条件成立时才出现)
item-size-textdata-disabled''(条件成立时才出现)
item-size-textdata-file-sizeundefined | String(file.size) | String(file.size)
item-previewdata-disabled''(条件成立时才出现)
item-previewdata-file-type(isRemote(file) ? file.type ?? '' : file.type) || 'un…
item-progressdata-disabled''(条件成立时才出现)
item-progressdata-stateupload?.status
item-delete-triggerdata-disabled''(条件成立时才出现)
item-delete-triggerdata-pressed''(条件成立时才出现)
item-delete-triggerdata-readonly''(条件成立时才出现)
item-delete-triggerdata-xh-action-control''
item-delete-triggerdata-xh-action-display'always'
item-delete-triggerdata-xh-action-profile'icon'
item-delete-triggerdata-xh-action-size'xs'
item-delete-triggerdata-xh-action-variant'ghost'
clear-triggerdata-disabled''(条件成立时才出现)
clear-triggerdata-empty''(条件成立时才出现)
clear-triggerdata-pressed''(条件成立时才出现)
clear-triggerdata-readonly''(条件成立时才出现)
clear-triggerdata-xh-action-control''
clear-triggerdata-xh-action-display'always'
clear-triggerdata-xh-action-profile'text'
clear-triggerdata-xh-action-size'sm'
clear-triggerdata-xh-action-variant'ghost'

CSS 变量 ​

本组件公开覆盖槽由独立皮肤的实际消费位生成;默认来源、作用部件和状态均与 CSS 同源。

变量部件CSS 属性状态默认来源说明
--xh-file-upload-clear-bg-activeclear-triggerbackground-colordisabled
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-_action-variant-bg-pressedfile-upload 的 clear-trigger 部件 background-color 覆盖槽。
--xh-file-upload-clear-bg-hoverclear-triggerbackground-colordisabled
hover
loading
not([data-disabled])
not([data-loading])
--xh-_action-variant-bg-hoverfile-upload 的 clear-trigger 部件 background-color 覆盖槽。
--xh-file-upload-clear-fgclear-triggercolordefault--xh-fg-mutedfile-upload 的 clear-trigger 部件 color 覆盖槽。
--xh-file-upload-clear-fg-hoverclear-triggercolordisabled
hover
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-fg-defaultfile-upload 的 clear-trigger 部件 color 覆盖槽。
--xh-file-upload-clear-font-sizeclear-triggerfont-sizedefault--xh-_action-profile-font-sizefile-upload 的 clear-trigger 部件 font-size 覆盖槽。
--xh-file-upload-clear-gapclear-triggergapdefault--xh-_action-profile-gapfile-upload 的 clear-trigger 部件 gap 覆盖槽。
--xh-file-upload-clear-hclear-triggerblock-size
inline-size
default
xh-action-profile=icon
--xh-_action-profile-visual-sizefile-upload 的 clear-trigger 部件 block-size、inline-size 覆盖槽。
--xh-file-upload-clear-pxclear-triggerpadding-inlinedefault--xh-_action-profile-padding-inlinefile-upload 的 clear-trigger 部件 padding-inline 覆盖槽。
--xh-file-upload-clear-radiusclear-triggerborder-radiusdefault--xh-shape-controlfile-upload 的 clear-trigger 部件 border-radius 覆盖槽。
--xh-file-upload-delete-bg-activeitem-delete-triggerbackground-colordisabled
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-_action-variant-bg-pressedfile-upload 的 item-delete-trigger 部件 background-color 覆盖槽。
--xh-file-upload-delete-bg-hoveritem-delete-triggerbackground-colordisabled
hover
loading
not([data-disabled])
not([data-loading])
--xh-_action-variant-bg-hoverfile-upload 的 item-delete-trigger 部件 background-color 覆盖槽。
--xh-file-upload-delete-fgitem-delete-triggercolordefault--xh-fg-mutedfile-upload 的 item-delete-trigger 部件 color 覆盖槽。
--xh-file-upload-delete-fg-hoveritem-delete-triggercolordisabled
hover
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-fg-danger-hoverfile-upload 的 item-delete-trigger 部件 color 覆盖槽。
--xh-file-upload-delete-radiusitem-delete-triggerborder-radiusdefault--xh-shape-controlfile-upload 的 item-delete-trigger 部件 border-radius 覆盖槽。
--xh-file-upload-delete-sizeitem-delete-triggerblock-size
inline-size
default
xh-action-profile=icon
--xh-_action-profile-visual-sizefile-upload 的 item-delete-trigger 部件 block-size、inline-size 覆盖槽。
--xh-file-upload-dropzone-bgdropzonebackgrounddefault--xh-bg-subtlefile-upload 的 dropzone 部件 background 覆盖槽。
--xh-file-upload-dropzone-bg-disableddropzonebackgrounddisabled--xh-bg-subtlefile-upload 的 dropzone 部件 background 覆盖槽。
--xh-file-upload-dropzone-bg-draggingdropzonebackgrounddragging--xh-bg-subtle-hoverfile-upload 的 dropzone 部件 background 覆盖槽。
--xh-file-upload-dropzone-bg-hoverdropzonebackgrounddisabled
dragging
hover
invalid
not([data-disabled], [data-readonly], [data-invalid], [data-dragging])
readonly
--xh-bg-subtle-hoverfile-upload 的 dropzone 部件 background 覆盖槽。
--xh-file-upload-dropzone-borderdropzoneborderdefault--xh-border-controlfile-upload 的 dropzone 部件 border 覆盖槽。
--xh-file-upload-dropzone-border-draggingdropzoneborder-colordragging--xh-bg-brandfile-upload 的 dropzone 部件 border-color 覆盖槽。
--xh-file-upload-dropzone-border-focusdropzoneborder-colordisabled
dragging
focus-visible
invalid
not([data-disabled], [data-invalid], [data-dragging])
--xh-_tonefile-upload 的 dropzone 部件 border-color 覆盖槽。
--xh-file-upload-dropzone-border-hoverdropzoneborder-colordisabled
dragging
hover
invalid
not([data-disabled], [data-readonly], [data-invalid], [data-dragging])
readonly
--xh-border-strongfile-upload 的 dropzone 部件 border-color 覆盖槽。
--xh-file-upload-dropzone-border-invaliddropzoneborder-colorinvalid--xh-border-invalidfile-upload 的 dropzone 部件 border-color 覆盖槽。
--xh-file-upload-dropzone-fgdropzonecolordefault--xh-fg-defaultfile-upload 的 dropzone 部件 color 覆盖槽。
--xh-file-upload-dropzone-font-sizedropzonefont-sizedefault--xh-text-body-sizefile-upload 的 dropzone 部件 font-size 覆盖槽。
--xh-file-upload-dropzone-gapdropzonegapdefault--xh-space-2file-upload 的 dropzone 部件 gap 覆盖槽。
--xh-file-upload-dropzone-min-hdropzonemin-block-sizedefault--xh-dropzone-min-hfile-upload 的 dropzone 部件 min-block-size 覆盖槽。
--xh-file-upload-dropzone-pxdropzonepadding-inlinedefault--xh-space-4file-upload 的 dropzone 部件 padding-inline 覆盖槽。
--xh-file-upload-dropzone-pydropzonepadding-blockdefault--xh-space-5file-upload 的 dropzone 部件 padding-block 覆盖槽。
--xh-file-upload-dropzone-radiusdropzoneborder-radiusdefault--xh-shape-controlfile-upload 的 dropzone 部件 border-radius 覆盖槽。
--xh-file-upload-gaplabel
root
gap
margin-block-end
default--xh-space-3file-upload 的 label、root 部件 gap、margin-block-end 覆盖槽。
--xh-file-upload-icon-sizeroot--xh-icon-sizedefault--xh-glyph-size-textfile-upload 的 root 部件 --xh-icon-size 覆盖槽。
--xh-file-upload-item-bgitembackgrounddefault--xh-bg-subtlefile-upload 的 item 部件 background 覆盖槽。
--xh-file-upload-item-bg-erroritembackgroundhas(> [data-part='item-progress'][data-state='error'])
state=closed
state=error
--xh-bg-surfacefile-upload 的 item 部件 background 覆盖槽。
--xh-file-upload-item-borderitemborderdefaulttransparentfile-upload 的 item 部件 border 覆盖槽。
--xh-file-upload-item-border-erroritemborder-colorhas(> [data-part='item-progress'][data-state='error'])
state=closed
state=error
transparentfile-upload 的 item 部件 border-color 覆盖槽。
--xh-file-upload-item-fgitemcolordefault--xh-fg-defaultfile-upload 的 item 部件 color 覆盖槽。
--xh-file-upload-item-fg-doneitembackground-colorhas(> [data-part='item-progress'][data-state='done'])
state=closed
state=done
--xh-fg-successfile-upload 的 item 部件 background-color 覆盖槽。
--xh-file-upload-item-fg-erroritem
item-name
background-color
color
has(> [data-part='item-progress'][data-state='error'])
state=closed
state=error
--xh-fg-dangerfile-upload 的 item、item-name 部件 background-color、color 覆盖槽。
--xh-file-upload-item-font-sizeitemfont-sizedefault--xh-text-body-sizefile-upload 的 item 部件 font-size 覆盖槽。
--xh-file-upload-item-gaplistgapdefault--xh-space-3file-upload 的 list 部件 gap 覆盖槽。
--xh-file-upload-item-inner-gapitemgapdefault--xh-space-3file-upload 的 item 部件 gap 覆盖槽。
--xh-file-upload-item-link-fgitem-linkcolordefault--xh-fg-brandfile-upload 的 item-link 部件 color 覆盖槽。
--xh-file-upload-item-link-fg-hoveritem-linkcolor@media (hover: hover)
disabled
hover
not([data-disabled])
--xh-fg-brand-strongfile-upload 的 item-link 部件 color 覆盖槽。
--xh-file-upload-item-link-radiusitem-linkborder-radiusdefault--xh-shape-insetfile-upload 的 item-link 部件 border-radius 覆盖槽。
--xh-file-upload-item-link-underline-offsetitem-linktext-underline-offsetdefault--xh-space-0_5file-upload 的 item-link 部件 text-underline-offset 覆盖槽。
--xh-file-upload-item-mark-sizeitemblock-size
inline-size
has(> [data-part='item-progress'][data-state='done'])
has(> [data-part='item-progress'][data-state='error'])
state=closed
state=done
state=error
--xh-control-indicator-sizefile-upload 的 item 部件 block-size、inline-size 覆盖槽。
--xh-file-upload-item-name-min-witem-namemin-inline-sizedefault--xh-control-min-wfile-upload 的 item-name 部件 min-inline-size 覆盖槽。
--xh-file-upload-item-progress-fillitem-progressbackgrounddefault--xh-bg-brandfile-upload 的 item-progress 部件 background 覆盖槽。
--xh-file-upload-item-progress-hitem-progressblock-sizedefault--xh-stroke-thickfile-upload 的 item-progress 部件 block-size 覆盖槽。
--xh-file-upload-item-progress-radiusitem-progressborder-radiusdefault--xh-shape-pillfile-upload 的 item-progress 部件 border-radius 覆盖槽。
--xh-file-upload-item-progress-trackitem-progressbackgrounddefault--xh-bg-subtlefile-upload 的 item-progress 部件 background 覆盖槽。
--xh-file-upload-item-progress-witem-progressinline-sizedefault--xh-control-h-mdfile-upload 的 item-progress 部件 inline-size 覆盖槽。
--xh-file-upload-item-pxitempadding-inlinedefault--xh-space-3file-upload 的 item 部件 padding-inline 覆盖槽。
--xh-file-upload-item-pyitempadding-blockdefault--xh-space-2file-upload 的 item 部件 padding-block 覆盖槽。
--xh-file-upload-item-radiusitemborder-radiusdefault--xh-shape-controlfile-upload 的 item 部件 border-radius 覆盖槽。
--xh-file-upload-label-fglabelcolordefault--xh-fg-mutedfile-upload 的 label 部件 color 覆盖槽。
--xh-file-upload-label-fg-disabledlabelcolordisabled--xh-fg-mutedfile-upload 的 label 部件 color 覆盖槽。
--xh-file-upload-label-font-sizelabelfont-sizedefault--xh-text-label-sizefile-upload 的 label 部件 font-size 覆盖槽。
--xh-file-upload-label-font-weightlabelfont-weightdefault--xh-text-label-weightfile-upload 的 label 部件 font-weight 覆盖槽。
--xh-file-upload-label-gaplabelmargin-block-enddefault--xh-space-2file-upload 的 label 部件 margin-block-end 覆盖槽。
--xh-file-upload-list-max-hlistmax-block-sizedefault--xh-viewport-h-mdfile-upload 的 list 部件 max-block-size 覆盖槽。
--xh-file-upload-preview-bgitem-previewbackgrounddefaulttransparentfile-upload 的 item-preview 部件 background 覆盖槽。
--xh-file-upload-preview-fgitem-previewcolordefault--xh-fg-brandfile-upload 的 item-preview 部件 color 覆盖槽。
--xh-file-upload-preview-fg-imageitem-previewcolorfile-type=image/--xh-fg-brandfile-upload 的 item-preview 部件 color 覆盖槽。
--xh-file-upload-preview-radiusitem-previewborder-radiusdefault--xh-shape-controlfile-upload 的 item-preview 部件 border-radius 覆盖槽。
--xh-file-upload-preview-sizeitem-previewblock-size
inline-size
default--xh-glyph-size-smfile-upload 的 item-preview 部件 block-size、inline-size 覆盖槽。
--xh-file-upload-size-fgitem-size-textcolordefault--xh-fg-subtlefile-upload 的 item-size-text 部件 color 覆盖槽。
--xh-file-upload-size-font-sizeitem-size-textfont-sizedefault--xh-text-caption-sizefile-upload 的 item-size-text 部件 font-size 覆盖槽。
--xh-file-upload-trigger-bgtrigger--xh-ink-surface
background-color
default
xh-ink-surface
--xh-_action-variant-bg-restfile-upload 的 trigger 部件 --xh-ink-surface、background-color 覆盖槽。
--xh-file-upload-trigger-bg-activetriggerbackground-colordisabled
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-_action-variant-bg-pressedfile-upload 的 trigger 部件 background-color 覆盖槽。
--xh-file-upload-trigger-bg-hovertriggerbackground-colordisabled
hover
loading
not([data-disabled])
not([data-loading])
--xh-_action-variant-bg-hoverfile-upload 的 trigger 部件 background-color 覆盖槽。
--xh-file-upload-trigger-bordertriggerborderdefault--xh-_action-variant-border-restfile-upload 的 trigger 部件 border 覆盖槽。
--xh-file-upload-trigger-fgtriggercolordefault
disabled
hover
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-_action-variant-fg-hover
--xh-_action-variant-fg-pressed
--xh-_action-variant-fg-rest
file-upload 的 trigger 部件 color 覆盖槽。
--xh-file-upload-trigger-font-sizetriggerfont-sizedefault--xh-_action-profile-font-sizefile-upload 的 trigger 部件 font-size 覆盖槽。
--xh-file-upload-trigger-font-weighttriggerfont-weightdefault--xh-text-label-weightfile-upload 的 trigger 部件 font-weight 覆盖槽。
--xh-file-upload-trigger-gaptriggergapdefault--xh-_action-profile-gapfile-upload 的 trigger 部件 gap 覆盖槽。
--xh-file-upload-trigger-htriggerblock-size
inline-size
default
xh-action-profile=icon
--xh-_action-profile-visual-sizefile-upload 的 trigger 部件 block-size、inline-size 覆盖槽。
--xh-file-upload-trigger-pxtriggerpadding-inlinedefault--xh-_action-profile-padding-inlinefile-upload 的 trigger 部件 padding-inline 覆盖槽。
--xh-file-upload-trigger-radiustriggerborder-radiusdefault--xh-shape-controlfile-upload 的 trigger 部件 border-radius 覆盖槽。
--xh-file-upload-trigger-shadow-hovertriggerbox-shadowdisabled
hover
loading
not([data-disabled])
not([data-loading])
nonefile-upload 的 trigger 部件 box-shadow 覆盖槽。

动效 ​

动效角色:按压 · 状态 · 指示与换位 · 出现 · 列表(见动效规范)。

共享关键帧 xh-fade-in · xh-fade-out · xh-item-in 由 family/motion.css 提供,皮肤 @import 它,单独引入仍成立;background-color · border-color · color · opacity · translate 走 transition 过渡。时长与缓动读动效令牌,改令牌即改全局节奏。

系统开启减弱动效时由令牌层统一收敛,皮肤不另作判断。

响应式 ​

皮肤另按输入能力分档:hover: hover:同一份皮肤在触屏与带指针的设备上不一样,与视口宽度无关。

RTL ​

皮肤用逻辑属性排布(inline-start 一族),dir="rtl" 下自动镜像;只认物理方向的量乘 --xh-direction-sign 换向,按就近的 dir 走。

Released under The MIT License